Merge pull request #74 from jorilallo/cleanup

Server Cleanup
This commit is contained in:
Jori Lallo
2017-05-29 13:43:52 -07:00
committed by GitHub
13 changed files with 87 additions and 105 deletions

View File

@@ -152,7 +152,7 @@ router.post('auth.slack', async ctx => {
} }
if (!teamExisted) { if (!teamExisted) {
await team.createFirstAtlas(user.id); await team.createFirstCollection(user.id);
} }
ctx.body = { ctx.body = {

View File

@@ -5,7 +5,7 @@ import _ from 'lodash';
import auth from './middlewares/authentication'; import auth from './middlewares/authentication';
import pagination from './middlewares/pagination'; import pagination from './middlewares/pagination';
import { presentCollection } from '../presenters'; import { presentCollection } from '../presenters';
import { Atlas } from '../models'; import { Collection } from '../models';
const router = new Router(); const router = new Router();
@@ -15,7 +15,7 @@ router.post('collections.create', auth(), async ctx => {
const user = ctx.state.user; const user = ctx.state.user;
const atlas = await Atlas.create({ const atlas = await Collection.create({
name, name,
description, description,
type: type || 'atlas', type: type || 'atlas',
@@ -33,7 +33,7 @@ router.post('collections.info', auth(), async ctx => {
ctx.assertPresent(id, 'id is required'); ctx.assertPresent(id, 'id is required');
const user = ctx.state.user; const user = ctx.state.user;
const atlas = await Atlas.findOne({ const atlas = await Collection.findOne({
where: { where: {
id, id,
teamId: user.teamId, teamId: user.teamId,
@@ -49,7 +49,7 @@ router.post('collections.info', auth(), async ctx => {
router.post('collections.list', auth(), pagination(), async ctx => { router.post('collections.list', auth(), pagination(), async ctx => {
const user = ctx.state.user; const user = ctx.state.user;
const collections = await Atlas.findAll({ const collections = await Collection.findAll({
where: { where: {
teamId: user.teamId, teamId: user.teamId,
}, },
@@ -58,7 +58,7 @@ router.post('collections.list', auth(), pagination(), async ctx => {
limit: ctx.state.pagination.limit, limit: ctx.state.pagination.limit,
}); });
// Atlases // Collectiones
let data = []; let data = [];
await Promise.all( await Promise.all(
collections.map(async atlas => { collections.map(async atlas => {
@@ -79,7 +79,7 @@ router.post('collections.updateNavigationTree', auth(), async ctx => {
ctx.assertPresent(id, 'id is required'); ctx.assertPresent(id, 'id is required');
const user = ctx.state.user; const user = ctx.state.user;
const atlas = await Atlas.findOne({ const atlas = await Collection.findOne({
where: { where: {
id, id,
teamId: user.teamId, teamId: user.teamId,

View File

@@ -8,7 +8,7 @@ const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z0-9]{10,15})$/;
import auth from './middlewares/authentication'; import auth from './middlewares/authentication';
// import pagination from './middlewares/pagination'; // import pagination from './middlewares/pagination';
import { presentDocument } from '../presenters'; import { presentDocument } from '../presenters';
import { Document, Atlas } from '../models'; import { Document, Collection } from '../models';
const router = new Router(); const router = new Router();
@@ -102,7 +102,7 @@ router.post('documents.create', auth(), async ctx => {
ctx.assertPresent(text, 'text is required'); ctx.assertPresent(text, 'text is required');
const user = ctx.state.user; const user = ctx.state.user;
const ownerCollection = await Atlas.findOne({ const ownerCollection = await Collection.findOne({
where: { where: {
id: collection, id: collection,
teamId: user.teamId, teamId: user.teamId,
@@ -176,7 +176,7 @@ router.post('documents.update', auth(), async ctx => {
// Update // Update
// TODO: Add locking // TODO: Add locking
const collection = await Atlas.findById(document.atlasId); const collection = await Collection.findById(document.atlasId);
if (collection.type === 'atlas') { if (collection.type === 'atlas') {
await collection.updateNavigationTree(); await collection.updateNavigationTree();
} }
@@ -195,7 +195,7 @@ router.post('documents.delete', auth(), async ctx => {
const user = ctx.state.user; const user = ctx.state.user;
const document = await getDocumentForId(id); const document = await getDocumentForId(id);
const collection = await Atlas.findById(document.atlasId); const collection = await Collection.findById(document.atlasId);
if (!document || document.teamId !== user.teamId) if (!document || document.teamId !== user.teamId)
throw httpErrors.BadRequest(); throw httpErrors.BadRequest();

View File

@@ -48,7 +48,7 @@ export default function auth({ require = true } = {}) {
}, },
}); });
} catch (e) { } catch (e) {
throw httpErrors.Unauthorized('Invalid api key'); throw httpErrors.Unauthorized('Invalid API key');
} }
if (!apiKey) throw httpErrors.Unauthorized('Invalid token'); if (!apiKey) throw httpErrors.Unauthorized('Invalid token');

View File

@@ -1,19 +1,17 @@
import httpErrors from 'http-errors'; import httpErrors from 'http-errors';
var querystring = require('querystring'); import querystring from 'querystring';
export default function pagination(options) { export default function pagination(options) {
return async function paginationMiddleware(ctx, next) { return async function paginationMiddleware(ctx, next) {
const opts = { const opts = {
...{ defaultLimit: 15,
defaultLimit: 15, maxLimit: 100,
maxLimit: 100,
},
...options, ...options,
}; };
let query = ctx.request.query; let query = ctx.request.query;
let limit = parseInt(query.limit); let limit = parseInt(query.limit, 10);
let offset = parseInt(query.offset); let offset = parseInt(query.offset, 10);
limit = isNaN(limit) ? opts.defaultLimit : limit; limit = isNaN(limit) ? opts.defaultLimit : limit;
offset = isNaN(offset) ? 0 : offset; offset = isNaN(offset) ? 0 : offset;
@@ -30,8 +28,7 @@ export default function pagination(options) {
query.limit = ctx.state.pagination.limit; query.limit = ctx.state.pagination.limit;
query.offset = ctx.state.pagination.offset + query.limit; query.offset = ctx.state.pagination.offset + query.limit;
ctx.state.pagination.nextPath = ctx.state.pagination.nextPath = `/api${ctx.request.path}?${querystring.stringify(query)}`;
'/api' + ctx.request.path + '?' + querystring.stringify(query);
return next(); return next();
}; };

View File

@@ -1,7 +1,7 @@
export default function subdomainRedirect(options) { export default function subdomainRedirect(options) {
return async function subdomainRedirectMiddleware(ctx, next) { return async function subdomainRedirectMiddleware(ctx, next) {
if (ctx.headers.host === 'beautifulatlas.com') { if (ctx.headers.host === 'beautifulatlas.com') {
ctx.redirect('https://www.' + ctx.headers.host + ctx.path); ctx.redirect(`https://www.${ctx.headers.host}${ctx.path}`);
} else { } else {
return next(); return next();
} }

View File

@@ -19,7 +19,7 @@ CREATE TRIGGER documents_tsvectorupdate BEFORE INSERT OR UPDATE
ON documents FOR EACH ROW EXECUTE PROCEDURE documents_search_trigger(); ON documents FOR EACH ROW EXECUTE PROCEDURE documents_search_trigger();
`; `;
const searchAtlas = ` const searchCollection = `
ALTER TABLE atlases ADD COLUMN "searchVector" tsvector; ALTER TABLE atlases ADD COLUMN "searchVector" tsvector;
CREATE INDEX atlases_tsv_idx ON atlases USING gin("searchVector"); CREATE INDEX atlases_tsv_idx ON atlases USING gin("searchVector");
@@ -37,7 +37,7 @@ ON atlases FOR EACH ROW EXECUTE PROCEDURE atlases_search_trigger();
`; `;
queryInterface.sequelize.query(searchDocument); queryInterface.sequelize.query(searchDocument);
queryInterface.sequelize.query(searchAtlas); queryInterface.sequelize.query(searchCollection);
}, },
down: function(queryInterface, Sequelize) { down: function(queryInterface, Sequelize) {

View File

@@ -6,9 +6,9 @@ import Document from './Document';
slug.defaults.mode = 'rfc3986'; slug.defaults.mode = 'rfc3986';
const allowedAtlasTypes = [['atlas', 'journal']]; const allowedCollectionTypes = [['atlas', 'journal']];
const Atlas = sequelize.define( const Collection = sequelize.define(
'atlas', 'atlas',
{ {
id: { id: {
@@ -19,7 +19,10 @@ const Atlas = sequelize.define(
urlId: { type: DataTypes.STRING, unique: true }, urlId: { type: DataTypes.STRING, unique: true },
name: DataTypes.STRING, name: DataTypes.STRING,
description: DataTypes.STRING, description: DataTypes.STRING,
type: { type: DataTypes.STRING, validate: { isIn: allowedAtlasTypes } }, type: {
type: DataTypes.STRING,
validate: { isIn: allowedCollectionTypes },
},
creatorId: DataTypes.UUID, creatorId: DataTypes.UUID,
/* type: atlas */ /* type: atlas */
@@ -210,6 +213,6 @@ const Atlas = sequelize.define(
} }
); );
Atlas.hasMany(Document, { as: 'documents', foreignKey: 'atlasId' }); Collection.hasMany(Document, { as: 'documents', foreignKey: 'atlasId' });
export default Atlas; export default Collection;

View File

@@ -1,5 +1,5 @@
import { DataTypes, sequelize } from '../sequelize'; import { DataTypes, sequelize } from '../sequelize';
import Atlas from './Atlas'; import Collection from './Collection';
import Document from './Document'; import Document from './Document';
import User from './User'; import User from './User';
@@ -17,10 +17,10 @@ const Team = sequelize.define(
}, },
{ {
instanceMethods: { instanceMethods: {
async createFirstAtlas(userId) { async createFirstCollection(userId) {
const atlas = await Atlas.create({ const atlas = await Collection.create({
name: this.name, name: this.name,
description: 'Your first Atlas', description: 'Your first Collection',
type: 'atlas', type: 'atlas',
teamId: this.id, teamId: this.id,
creatorId: userId, creatorId: userId,
@@ -37,7 +37,7 @@ const Team = sequelize.define(
} }
); );
Team.hasMany(Atlas, { as: 'atlases' }); Team.hasMany(Collection, { as: 'atlases' });
Team.hasMany(Document, { as: 'documents' }); Team.hasMany(Document, { as: 'documents' });
Team.hasMany(User, { as: 'users' }); Team.hasMany(User, { as: 'users' });

View File

@@ -1,8 +1,8 @@
import User from './User'; import User from './User';
import Team from './Team'; import Team from './Team';
import Atlas from './Atlas'; import Collection from './Collection';
import Document from './Document'; import Document from './Document';
import Revision from './Revision'; import Revision from './Revision';
import ApiKey from './ApiKey'; import ApiKey from './ApiKey';
export { User, Team, Atlas, Document, Revision, ApiKey }; export { User, Team, Collection, Document, Revision, ApiKey };

View File

@@ -1,19 +1,17 @@
import _ from 'lodash'; import _ from 'lodash';
import { Document, Atlas, User } from './models'; import { Document, Collection, User } from './models';
import presentUser from './presenters/user'; import presentUser from './presenters/user';
export { presentUser }; export { presentUser };
export function presentTeam(ctx, team) { export async function presentTeam(ctx, team) {
ctx.cache.set(team.id, team); ctx.cache.set(team.id, team);
return new Promise(async (resolve, _reject) => { return {
resolve({ id: team.id,
id: team.id, name: team.name,
name: team.name, };
});
});
} }
export async function presentDocument(ctx, document, options) { export async function presentDocument(ctx, document, options) {
@@ -42,7 +40,7 @@ export async function presentDocument(ctx, document, options) {
if (options.includeCollection) { if (options.includeCollection) {
data.collection = await ctx.cache.get(document.atlasId, async () => { data.collection = await ctx.cache.get(document.atlasId, async () => {
const collection = await Atlas.findOne({ const collection = await Collection.findOne({
where: { where: {
id: document.atlasId, id: document.atlasId,
}, },
@@ -77,55 +75,49 @@ export async function presentDocument(ctx, document, options) {
return data; return data;
} }
export function presentCollection( export async function presentCollection(
ctx, ctx,
collection, collection,
includeRecentDocuments = false includeRecentDocuments = false
) { ) {
ctx.cache.set(collection.id, collection); ctx.cache.set(collection.id, collection);
return new Promise(async (resolve, _reject) => { const data = {
const data = { id: collection.id,
id: collection.id, url: collection.getUrl(),
url: collection.getUrl(), name: collection.name,
name: collection.name, description: collection.description,
description: collection.description, type: collection.type,
type: collection.type, createdAt: collection.createdAt,
createdAt: collection.createdAt, updatedAt: collection.updatedAt,
updatedAt: collection.updatedAt, };
};
if (collection.type === 'atlas') if (collection.type === 'atlas')
data.navigationTree = collection.navigationTree; data.navigationTree = collection.navigationTree;
if (includeRecentDocuments) { if (includeRecentDocuments) {
const documents = await Document.findAll({ const documents = await Document.findAll({
where: { where: {
atlasId: collection.id, atlasId: collection.id,
}, },
limit: 10, limit: 10,
order: [['updatedAt', 'DESC']], order: [['updatedAt', 'DESC']],
}); });
const recentDocuments = []; const recentDocuments = [];
await Promise.all( await Promise.all(
documents.map(async document => { documents.map(async document => {
recentDocuments.push( recentDocuments.push(
await presentDocument(ctx, document, { await presentDocument(ctx, document, {
includeCollaborators: true, includeCollaborators: true,
}) })
); );
}) })
); );
data.recentDocuments = _.orderBy( data.recentDocuments = _.orderBy(recentDocuments, ['updatedAt'], ['desc']);
recentDocuments, }
['updatedAt'],
['desc']
);
}
resolve(data); return data;
});
} }
export function presentApiKey(ctx, key) { export function presentApiKey(ctx, key) {

View File

@@ -1,15 +1,15 @@
const presentUser = (ctx, user) => { // @flow
import User from '../models/User';
async function presentUser(ctx: Object, user: User) {
ctx.cache.set(user.id, user); ctx.cache.set(user.id, user);
return new Promise(async (resolve, _reject) => { return {
const data = { id: user.id,
id: user.id, username: user.username,
username: user.username, name: user.name,
name: user.name, avatarUrl: user.slackData ? user.slackData.image_192 : null,
avatarUrl: user.slackData ? user.slackData.image_192 : null, };
}; }
resolve(data);
});
};
export default presentUser; export default presentUser;

View File

@@ -32,15 +32,5 @@
<div class="header"></div> <div class="header"></div>
</div> </div>
</div> </div>
<script type="text/javascript">
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker.register('/service-worker.js')
// .then(function(reg) {
// console.log('SW registration succeeded');
// }).catch(function(error) {
// console.log('SW registration failed: ' + error);
// });
// };
</script>
</body> </body>
</html> </html>