@@ -152,7 +152,7 @@ router.post('auth.slack', async ctx => {
|
||||
}
|
||||
|
||||
if (!teamExisted) {
|
||||
await team.createFirstAtlas(user.id);
|
||||
await team.createFirstCollection(user.id);
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
|
||||
@@ -5,7 +5,7 @@ import _ from 'lodash';
|
||||
import auth from './middlewares/authentication';
|
||||
import pagination from './middlewares/pagination';
|
||||
import { presentCollection } from '../presenters';
|
||||
import { Atlas } from '../models';
|
||||
import { Collection } from '../models';
|
||||
|
||||
const router = new Router();
|
||||
|
||||
@@ -15,7 +15,7 @@ router.post('collections.create', auth(), async ctx => {
|
||||
|
||||
const user = ctx.state.user;
|
||||
|
||||
const atlas = await Atlas.create({
|
||||
const atlas = await Collection.create({
|
||||
name,
|
||||
description,
|
||||
type: type || 'atlas',
|
||||
@@ -33,7 +33,7 @@ router.post('collections.info', auth(), async ctx => {
|
||||
ctx.assertPresent(id, 'id is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const atlas = await Atlas.findOne({
|
||||
const atlas = await Collection.findOne({
|
||||
where: {
|
||||
id,
|
||||
teamId: user.teamId,
|
||||
@@ -49,7 +49,7 @@ router.post('collections.info', auth(), async ctx => {
|
||||
|
||||
router.post('collections.list', auth(), pagination(), async ctx => {
|
||||
const user = ctx.state.user;
|
||||
const collections = await Atlas.findAll({
|
||||
const collections = await Collection.findAll({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
@@ -58,7 +58,7 @@ router.post('collections.list', auth(), pagination(), async ctx => {
|
||||
limit: ctx.state.pagination.limit,
|
||||
});
|
||||
|
||||
// Atlases
|
||||
// Collectiones
|
||||
let data = [];
|
||||
await Promise.all(
|
||||
collections.map(async atlas => {
|
||||
@@ -79,7 +79,7 @@ router.post('collections.updateNavigationTree', auth(), async ctx => {
|
||||
ctx.assertPresent(id, 'id is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const atlas = await Atlas.findOne({
|
||||
const atlas = await Collection.findOne({
|
||||
where: {
|
||||
id,
|
||||
teamId: user.teamId,
|
||||
|
||||
@@ -8,7 +8,7 @@ const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z0-9]{10,15})$/;
|
||||
import auth from './middlewares/authentication';
|
||||
// import pagination from './middlewares/pagination';
|
||||
import { presentDocument } from '../presenters';
|
||||
import { Document, Atlas } from '../models';
|
||||
import { Document, Collection } from '../models';
|
||||
|
||||
const router = new Router();
|
||||
|
||||
@@ -102,7 +102,7 @@ router.post('documents.create', auth(), async ctx => {
|
||||
ctx.assertPresent(text, 'text is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const ownerCollection = await Atlas.findOne({
|
||||
const ownerCollection = await Collection.findOne({
|
||||
where: {
|
||||
id: collection,
|
||||
teamId: user.teamId,
|
||||
@@ -176,7 +176,7 @@ router.post('documents.update', auth(), async ctx => {
|
||||
|
||||
// Update
|
||||
// TODO: Add locking
|
||||
const collection = await Atlas.findById(document.atlasId);
|
||||
const collection = await Collection.findById(document.atlasId);
|
||||
if (collection.type === 'atlas') {
|
||||
await collection.updateNavigationTree();
|
||||
}
|
||||
@@ -195,7 +195,7 @@ router.post('documents.delete', auth(), async ctx => {
|
||||
|
||||
const user = ctx.state.user;
|
||||
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)
|
||||
throw httpErrors.BadRequest();
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function auth({ require = true } = {}) {
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw httpErrors.Unauthorized('Invalid api key');
|
||||
throw httpErrors.Unauthorized('Invalid API key');
|
||||
}
|
||||
|
||||
if (!apiKey) throw httpErrors.Unauthorized('Invalid token');
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import httpErrors from 'http-errors';
|
||||
var querystring = require('querystring');
|
||||
import querystring from 'querystring';
|
||||
|
||||
export default function pagination(options) {
|
||||
return async function paginationMiddleware(ctx, next) {
|
||||
const opts = {
|
||||
...{
|
||||
defaultLimit: 15,
|
||||
maxLimit: 100,
|
||||
},
|
||||
defaultLimit: 15,
|
||||
maxLimit: 100,
|
||||
...options,
|
||||
};
|
||||
|
||||
let query = ctx.request.query;
|
||||
let limit = parseInt(query.limit);
|
||||
let offset = parseInt(query.offset);
|
||||
let limit = parseInt(query.limit, 10);
|
||||
let offset = parseInt(query.offset, 10);
|
||||
limit = isNaN(limit) ? opts.defaultLimit : limit;
|
||||
offset = isNaN(offset) ? 0 : offset;
|
||||
|
||||
@@ -30,8 +28,7 @@ export default function pagination(options) {
|
||||
|
||||
query.limit = ctx.state.pagination.limit;
|
||||
query.offset = ctx.state.pagination.offset + query.limit;
|
||||
ctx.state.pagination.nextPath =
|
||||
'/api' + ctx.request.path + '?' + querystring.stringify(query);
|
||||
ctx.state.pagination.nextPath = `/api${ctx.request.path}?${querystring.stringify(query)}`;
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default function subdomainRedirect(options) {
|
||||
return async function subdomainRedirectMiddleware(ctx, next) {
|
||||
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 {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ CREATE TRIGGER documents_tsvectorupdate BEFORE INSERT OR UPDATE
|
||||
ON documents FOR EACH ROW EXECUTE PROCEDURE documents_search_trigger();
|
||||
`;
|
||||
|
||||
const searchAtlas = `
|
||||
const searchCollection = `
|
||||
ALTER TABLE atlases ADD COLUMN "searchVector" tsvector;
|
||||
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(searchAtlas);
|
||||
queryInterface.sequelize.query(searchCollection);
|
||||
},
|
||||
|
||||
down: function(queryInterface, Sequelize) {
|
||||
|
||||
@@ -6,9 +6,9 @@ import Document from './Document';
|
||||
|
||||
slug.defaults.mode = 'rfc3986';
|
||||
|
||||
const allowedAtlasTypes = [['atlas', 'journal']];
|
||||
const allowedCollectionTypes = [['atlas', 'journal']];
|
||||
|
||||
const Atlas = sequelize.define(
|
||||
const Collection = sequelize.define(
|
||||
'atlas',
|
||||
{
|
||||
id: {
|
||||
@@ -19,7 +19,10 @@ const Atlas = sequelize.define(
|
||||
urlId: { type: DataTypes.STRING, unique: true },
|
||||
name: DataTypes.STRING,
|
||||
description: DataTypes.STRING,
|
||||
type: { type: DataTypes.STRING, validate: { isIn: allowedAtlasTypes } },
|
||||
type: {
|
||||
type: DataTypes.STRING,
|
||||
validate: { isIn: allowedCollectionTypes },
|
||||
},
|
||||
creatorId: DataTypes.UUID,
|
||||
|
||||
/* 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;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataTypes, sequelize } from '../sequelize';
|
||||
import Atlas from './Atlas';
|
||||
import Collection from './Collection';
|
||||
import Document from './Document';
|
||||
import User from './User';
|
||||
|
||||
@@ -17,10 +17,10 @@ const Team = sequelize.define(
|
||||
},
|
||||
{
|
||||
instanceMethods: {
|
||||
async createFirstAtlas(userId) {
|
||||
const atlas = await Atlas.create({
|
||||
async createFirstCollection(userId) {
|
||||
const atlas = await Collection.create({
|
||||
name: this.name,
|
||||
description: 'Your first Atlas',
|
||||
description: 'Your first Collection',
|
||||
type: 'atlas',
|
||||
teamId: this.id,
|
||||
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(User, { as: 'users' });
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import User from './User';
|
||||
import Team from './Team';
|
||||
import Atlas from './Atlas';
|
||||
import Collection from './Collection';
|
||||
import Document from './Document';
|
||||
import Revision from './Revision';
|
||||
import ApiKey from './ApiKey';
|
||||
|
||||
export { User, Team, Atlas, Document, Revision, ApiKey };
|
||||
export { User, Team, Collection, Document, Revision, ApiKey };
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import _ from 'lodash';
|
||||
import { Document, Atlas, User } from './models';
|
||||
import { Document, Collection, User } from './models';
|
||||
|
||||
import presentUser from './presenters/user';
|
||||
|
||||
export { presentUser };
|
||||
|
||||
export function presentTeam(ctx, team) {
|
||||
export async function presentTeam(ctx, team) {
|
||||
ctx.cache.set(team.id, team);
|
||||
|
||||
return new Promise(async (resolve, _reject) => {
|
||||
resolve({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
});
|
||||
});
|
||||
return {
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
};
|
||||
}
|
||||
|
||||
export async function presentDocument(ctx, document, options) {
|
||||
@@ -42,7 +40,7 @@ export async function presentDocument(ctx, document, options) {
|
||||
|
||||
if (options.includeCollection) {
|
||||
data.collection = await ctx.cache.get(document.atlasId, async () => {
|
||||
const collection = await Atlas.findOne({
|
||||
const collection = await Collection.findOne({
|
||||
where: {
|
||||
id: document.atlasId,
|
||||
},
|
||||
@@ -77,55 +75,49 @@ export async function presentDocument(ctx, document, options) {
|
||||
return data;
|
||||
}
|
||||
|
||||
export function presentCollection(
|
||||
export async function presentCollection(
|
||||
ctx,
|
||||
collection,
|
||||
includeRecentDocuments = false
|
||||
) {
|
||||
ctx.cache.set(collection.id, collection);
|
||||
|
||||
return new Promise(async (resolve, _reject) => {
|
||||
const data = {
|
||||
id: collection.id,
|
||||
url: collection.getUrl(),
|
||||
name: collection.name,
|
||||
description: collection.description,
|
||||
type: collection.type,
|
||||
createdAt: collection.createdAt,
|
||||
updatedAt: collection.updatedAt,
|
||||
};
|
||||
const data = {
|
||||
id: collection.id,
|
||||
url: collection.getUrl(),
|
||||
name: collection.name,
|
||||
description: collection.description,
|
||||
type: collection.type,
|
||||
createdAt: collection.createdAt,
|
||||
updatedAt: collection.updatedAt,
|
||||
};
|
||||
|
||||
if (collection.type === 'atlas')
|
||||
data.navigationTree = collection.navigationTree;
|
||||
if (collection.type === 'atlas')
|
||||
data.navigationTree = collection.navigationTree;
|
||||
|
||||
if (includeRecentDocuments) {
|
||||
const documents = await Document.findAll({
|
||||
where: {
|
||||
atlasId: collection.id,
|
||||
},
|
||||
limit: 10,
|
||||
order: [['updatedAt', 'DESC']],
|
||||
});
|
||||
if (includeRecentDocuments) {
|
||||
const documents = await Document.findAll({
|
||||
where: {
|
||||
atlasId: collection.id,
|
||||
},
|
||||
limit: 10,
|
||||
order: [['updatedAt', 'DESC']],
|
||||
});
|
||||
|
||||
const recentDocuments = [];
|
||||
await Promise.all(
|
||||
documents.map(async document => {
|
||||
recentDocuments.push(
|
||||
await presentDocument(ctx, document, {
|
||||
includeCollaborators: true,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
data.recentDocuments = _.orderBy(
|
||||
recentDocuments,
|
||||
['updatedAt'],
|
||||
['desc']
|
||||
);
|
||||
}
|
||||
const recentDocuments = [];
|
||||
await Promise.all(
|
||||
documents.map(async document => {
|
||||
recentDocuments.push(
|
||||
await presentDocument(ctx, document, {
|
||||
includeCollaborators: true,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
data.recentDocuments = _.orderBy(recentDocuments, ['updatedAt'], ['desc']);
|
||||
}
|
||||
|
||||
resolve(data);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export function presentApiKey(ctx, key) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
return new Promise(async (resolve, _reject) => {
|
||||
const data = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
avatarUrl: user.slackData ? user.slackData.image_192 : null,
|
||||
};
|
||||
resolve(data);
|
||||
});
|
||||
};
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
avatarUrl: user.slackData ? user.slackData.image_192 : null,
|
||||
};
|
||||
}
|
||||
|
||||
export default presentUser;
|
||||
|
||||
@@ -32,15 +32,5 @@
|
||||
<div class="header"></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>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user