New database with migrations
This commit is contained in:
parent
f2732aacab
commit
24e02bfdc4
|
@ -0,0 +1,10 @@
|
|||
require('localenv');
|
||||
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
'config': path.resolve('server/config', 'database.json'),
|
||||
'migrations-path': path.resolve('server', 'migrations'),
|
||||
'models-path': path.resolve('server', 'models'),
|
||||
'seeders-path': path.resolve('server/models', 'fixtures'),
|
||||
}
|
|
@ -11,7 +11,8 @@
|
|||
"start": "cross-env NODE_ENV=development DEBUG=1 ./node_modules/.bin/nodemon --watch server index.js",
|
||||
"lint": "eslint src",
|
||||
"deploy": "git push heroku master",
|
||||
"heroku-postbuild": "npm run build"
|
||||
"heroku-postbuild": "npm run build && npm run sequelize db:migrate",
|
||||
"sequelize": "./node_modules/.bin/sequelize"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -97,7 +98,7 @@
|
|||
"safestart": "^0.8.0",
|
||||
"sass-loader": "^3.2.0",
|
||||
"sequelize": "^3.21.0",
|
||||
"sequelize-cli": "^2.3.1",
|
||||
"sequelize-cli": "^2.4.0",
|
||||
"sequelize-encrypted": "^0.1.0",
|
||||
"slug": "^0.9.1",
|
||||
"style-loader": "^0.13.0",
|
||||
|
|
|
@ -13,11 +13,11 @@ router.post('atlases.info', auth(), async (ctx) => {
|
|||
let { id } = ctx.request.body;
|
||||
ctx.assertPresent(id, 'id is required');
|
||||
|
||||
const team = await ctx.state.user.getTeam();
|
||||
const user = ctx.state.user;
|
||||
const atlas = await Atlas.findOne({
|
||||
where: {
|
||||
id: id,
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -30,10 +30,10 @@ router.post('atlases.info', auth(), async (ctx) => {
|
|||
|
||||
|
||||
router.post('atlases.list', auth(), pagination(), async (ctx) => {
|
||||
const team = await ctx.state.user.getTeam();
|
||||
const user = ctx.state.user;
|
||||
const atlases = await Atlas.findAll({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
},
|
||||
order: [
|
||||
['updatedAt', 'DESC'],
|
||||
|
|
|
@ -40,13 +40,27 @@ router.post('auth.slack', async (ctx) => {
|
|||
const authResponse = await fetch(`https://slack.com/api/auth.test?token=${data.access_token}`);
|
||||
const authData = await authResponse.json();
|
||||
|
||||
// Team
|
||||
let team = await Team.findOne({ where: { slackId: data.team.id } });
|
||||
if (!team) {
|
||||
team = await Team.create({
|
||||
name: data.team.name,
|
||||
slackId: data.team.id,
|
||||
slackData: data.team,
|
||||
});
|
||||
const atlas = await team.createFirstAtlas();
|
||||
} else {
|
||||
team.name = data.team.name;
|
||||
team.slackData = data.team;
|
||||
team = await team.save();
|
||||
}
|
||||
|
||||
if (user) {
|
||||
user.slackAccessToken = data.access_token;
|
||||
user.slackData = data.user;
|
||||
user = await user.save();
|
||||
} else {
|
||||
// Existing user
|
||||
user = await User.create({
|
||||
user = await team.createUser({
|
||||
slackId: data.user.id,
|
||||
username: authData.user,
|
||||
name: data.user.name,
|
||||
|
@ -56,30 +70,11 @@ router.post('auth.slack', async (ctx) => {
|
|||
});
|
||||
}
|
||||
|
||||
// Team
|
||||
let team = await Team.findOne({ where: { slackId: data.team.id } });
|
||||
if (!team) {
|
||||
team = await Team.create({
|
||||
name: data.team.name,
|
||||
slackId: data.team.id,
|
||||
slackData: data.team,
|
||||
});
|
||||
} else {
|
||||
// Update data
|
||||
team.name = data.team.name;
|
||||
team.slackData = data.team;
|
||||
team = await team.save();
|
||||
}
|
||||
|
||||
// Add to correct team
|
||||
user.setTeam(team);
|
||||
|
||||
ctx.body = { data: {
|
||||
user: await presentUser(user),
|
||||
team: await presentTeam(team),
|
||||
accessToken: user.getJwtToken(),
|
||||
}};
|
||||
console.log("enf")
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -23,8 +23,8 @@ router.post('documents.info', auth({ require: false }), async (ctx) => {
|
|||
if (document.private) {
|
||||
if (!ctx.state.user) throw httpErrors.NotFound();
|
||||
|
||||
const team = await ctx.state.user.getTeam();
|
||||
if (document.teamId !== team.id) {
|
||||
const user = await ctx.state.user;
|
||||
if (document.teamId !== user.teamId) {
|
||||
throw httpErrors.NotFound();
|
||||
}
|
||||
|
||||
|
@ -52,11 +52,10 @@ router.post('documents.create', auth(), async (ctx) => {
|
|||
ctx.assertPresent(text, 'text is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const team = await user.getTeam();
|
||||
const ownerAtlas = await Atlas.findOne({
|
||||
where: {
|
||||
id: atlas,
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -64,7 +63,7 @@ router.post('documents.create', auth(), async (ctx) => {
|
|||
|
||||
const document = await Document.create({
|
||||
atlasId: ownerAtlas.id,
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
userId: user.id,
|
||||
title: title,
|
||||
text: text,
|
||||
|
@ -86,11 +85,10 @@ router.post('documents.update', auth(), async (ctx) => {
|
|||
ctx.assertPresent(text, 'text is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const team = await user.getTeam();
|
||||
let document = await Document.findOne({
|
||||
where: {
|
||||
id: id,
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -112,11 +110,10 @@ router.post('documents.delete', auth(), async (ctx) => {
|
|||
ctx.assertPresent(id, 'id is required');
|
||||
|
||||
const user = ctx.state.user;
|
||||
const team = await user.getTeam();
|
||||
let document = await Document.findOne({
|
||||
where: {
|
||||
id: id,
|
||||
teamId: team.id,
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"development": {
|
||||
"use_env_variable": "DATABASE_URL",
|
||||
"dialect": "postgres"
|
||||
},
|
||||
"test": {
|
||||
"use_env_variable": "DATABASE_URL",
|
||||
"dialect": "postgres"
|
||||
},
|
||||
"production": {
|
||||
"use_env_variable": "DATABASE_URL",
|
||||
"dialect": "postgres"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (queryInterface, Sequelize) {
|
||||
queryInterface.createTable('atlases', {
|
||||
id:
|
||||
{ type: 'UUID',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: true },
|
||||
name:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
description:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
type:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
atlasStructure:
|
||||
{ type: 'JSONB',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
createdAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
updatedAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
teamId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false } }
|
||||
);
|
||||
|
||||
// documents
|
||||
queryInterface.createTable('documents', {
|
||||
id:
|
||||
{ type: 'UUID',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: true },
|
||||
urlId:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
private:
|
||||
{ type: 'BOOLEAN',
|
||||
allowNull: false,
|
||||
defaultValue: true,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
title:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
text:
|
||||
{ type: 'TEXT',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
html:
|
||||
{ type: 'TEXT',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
preview:
|
||||
{ type: 'TEXT',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
createdAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
updatedAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
userId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
atlasId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
rootDocumentForId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
teamId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false }
|
||||
});
|
||||
|
||||
queryInterface.createTable('teams', {
|
||||
id:
|
||||
{ type: 'UUID',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: true },
|
||||
name:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
slackId:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: true },
|
||||
slackData:
|
||||
{ type: 'JSONB',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
createdAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
updatedAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false } }
|
||||
);
|
||||
|
||||
queryInterface.createTable('users', {
|
||||
id:
|
||||
{ type: 'UUID',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: true },
|
||||
email:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
username:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
name:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
isAdmin:
|
||||
{ type: 'BOOLEAN',
|
||||
allowNull: true,
|
||||
defaultValue: false,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
slackAccessToken:
|
||||
{ type: 'bytea',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
slackId:
|
||||
{ type: 'CHARACTER VARYING',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
unique: true,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
slackData:
|
||||
{ type: 'JSONB',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
jwtSecret:
|
||||
{ type: 'bytea',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
createdAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
updatedAt:
|
||||
{ type: 'TIMESTAMP WITH TIME ZONE',
|
||||
allowNull: false,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false },
|
||||
teamId:
|
||||
{ type: 'UUID',
|
||||
allowNull: true,
|
||||
defaultValue: null,
|
||||
special: [],
|
||||
primaryKey: false }
|
||||
});
|
||||
},
|
||||
|
||||
down: function (queryInterface, Sequelize) {
|
||||
queryInterface.dropAllTables();
|
||||
}
|
||||
};
|
|
@ -2,7 +2,7 @@ import {
|
|||
DataTypes,
|
||||
sequelize,
|
||||
} from '../sequelize';
|
||||
import Team from './Team';
|
||||
import Document from './Document';
|
||||
|
||||
const allowedAtlasTypes = [['atlas', 'journal']];
|
||||
|
||||
|
@ -11,8 +11,33 @@ const Atlas = sequelize.define('atlas', {
|
|||
name: DataTypes.STRING,
|
||||
description: DataTypes.STRING,
|
||||
type: { type: DataTypes.STRING, validate: { isIn: allowedAtlasTypes }},
|
||||
|
||||
/* type: atlas */
|
||||
atlasStructure: DataTypes.JSONB,
|
||||
}, {
|
||||
tableName: 'atlases',
|
||||
hooks: {
|
||||
// beforeValidate: (doc) => {
|
||||
// doc.urlId = randomstring.generate(15);
|
||||
// },
|
||||
// beforeCreate: (doc) => {
|
||||
// doc.html = convertToMarkdown(doc.text);
|
||||
// doc.preview = truncateMarkdown(doc.text, 160);
|
||||
// },
|
||||
// beforeUpdate: (doc) => {
|
||||
// doc.html = convertToMarkdown(doc.text);
|
||||
// doc.preview = truncateMarkdown(doc.text, 160);
|
||||
// },
|
||||
},
|
||||
instanceMethods: {
|
||||
// buildUrl() {
|
||||
// const slugifiedTitle = slug(this.title);
|
||||
// return `${slugifiedTitle}-${this.urlId}`;
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
Atlas.belongsTo(Team);
|
||||
Atlas.hasMany(Document, { as: 'documents', foreignKey: 'atlasId' });
|
||||
Atlas.hasOne(Document, { as: 'rootDocument', foreignKey: 'rootDocumentForId', constraints: false });
|
||||
|
||||
export default Atlas;
|
||||
|
|
|
@ -10,8 +10,6 @@ import {
|
|||
import {
|
||||
truncateMarkdown,
|
||||
} from '../utils/truncate';
|
||||
import Atlas from './Atlas';
|
||||
import Team from './Team';
|
||||
import User from './User';
|
||||
|
||||
slug.defaults.mode ='rfc3986';
|
||||
|
@ -51,8 +49,6 @@ const Document = sequelize.define('document', {
|
|||
}
|
||||
});
|
||||
|
||||
Document.belongsTo(Atlas, { as: 'atlas' });
|
||||
Document.belongsTo(Team);
|
||||
Document.belongsTo(User);
|
||||
|
||||
export default Document;
|
||||
|
|
|
@ -2,6 +2,9 @@ import {
|
|||
DataTypes,
|
||||
sequelize,
|
||||
} from '../sequelize';
|
||||
import Atlas from './Atlas';
|
||||
import Document from './Document';
|
||||
import User from './User';
|
||||
|
||||
const Team = sequelize.define('team', {
|
||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||
|
@ -9,6 +12,17 @@ const Team = sequelize.define('team', {
|
|||
slackId: { type: DataTypes.STRING, unique: true },
|
||||
slackData: DataTypes.JSONB,
|
||||
}, {
|
||||
instanceMethods: {
|
||||
async createFirstAtlas() {
|
||||
const atlas = await Atlas.create({
|
||||
name: this.name,
|
||||
description: 'Your first Atlas',
|
||||
type: 'journal',
|
||||
teamId: this.id,
|
||||
});
|
||||
return atlas;
|
||||
}
|
||||
},
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
|
@ -17,4 +31,8 @@ const Team = sequelize.define('team', {
|
|||
],
|
||||
});
|
||||
|
||||
Team.hasMany(Atlas, { as: 'atlases' });
|
||||
Team.hasMany(Document, { as: 'documents' });
|
||||
Team.hasMany(User, { as: 'users' });
|
||||
|
||||
export default Team;
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
sequelize,
|
||||
encryptedFields
|
||||
} from '../sequelize';
|
||||
import Team from './Team';
|
||||
|
||||
import JWT from 'jsonwebtoken';
|
||||
|
||||
|
@ -39,8 +38,5 @@ const setRandomJwtSecret = (model) => {
|
|||
};
|
||||
|
||||
User.beforeCreate(setRandomJwtSecret);
|
||||
User.belongsTo(Team);
|
||||
|
||||
sequelize.sync();
|
||||
|
||||
export default User;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import _orderBy from 'lodash.orderby';
|
||||
import Document from './models/Document';
|
||||
import { Document, Atlas } from './models';
|
||||
|
||||
export function presentUser(user) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
|
@ -65,12 +65,14 @@ export async function presentDocument(document, includeAtlas=false) {
|
|||
private: document.private,
|
||||
createdAt: document.createdAt,
|
||||
updatedAt: document.updatedAt,
|
||||
atlas: document.atlaId,
|
||||
atlas: document.atlasId,
|
||||
team: document.teamId,
|
||||
}
|
||||
|
||||
if (includeAtlas) {
|
||||
const atlas = await document.getAtlas();
|
||||
const atlas = await Atlas.findOne({ where: {
|
||||
id: document.atlasId,
|
||||
}});
|
||||
data.atlas = await presentAtlas(atlas, false);
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue