Post to Slack (#603)
* Migrations
* WIP: Integration model, slack perms / hooks
* So so rough it pains me. Building this new model is revealing just how much needs to be refactored
* Working connect and post
* Cleanup UI, upating documents
* Show when slack command is connected
* stash
* 💚
* Add documents.update trigger
* Authorization, tidying
* Fixed integration policy
* pick integration presenter keys
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable flowtype/require-valid-file-annotation */
|
||||
import { flushdb, seed } from '../test/support';
|
||||
import { Collection, Document } from '../models';
|
||||
import uuid from 'uuid';
|
||||
|
||||
beforeEach(flushdb);
|
||||
beforeEach(jest.resetAllMocks);
|
||||
@@ -15,34 +16,37 @@ describe('#getUrl', () => {
|
||||
describe('#addDocumentToStructure', async () => {
|
||||
test('should add as last element without index', async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuid.v4();
|
||||
const newDocument = new Document({
|
||||
id: '5',
|
||||
id,
|
||||
title: 'New end node',
|
||||
parentDocumentId: null,
|
||||
});
|
||||
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure.length).toBe(3);
|
||||
expect(collection.documentStructure[2].id).toBe('5');
|
||||
expect(collection.documentStructure[2].id).toBe(id);
|
||||
});
|
||||
|
||||
test('should add with an index', async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuid.v4();
|
||||
const newDocument = new Document({
|
||||
id: '5',
|
||||
id,
|
||||
title: 'New end node',
|
||||
parentDocumentId: null,
|
||||
});
|
||||
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure.length).toBe(3);
|
||||
expect(collection.documentStructure[1].id).toBe('5');
|
||||
expect(collection.documentStructure[1].id).toBe(id);
|
||||
});
|
||||
|
||||
test('should add as a child if with parent', async () => {
|
||||
const { collection, document } = await seed();
|
||||
const id = uuid.v4();
|
||||
const newDocument = new Document({
|
||||
id: '5',
|
||||
id,
|
||||
title: 'New end node',
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
@@ -51,18 +55,19 @@ describe('#addDocumentToStructure', async () => {
|
||||
expect(collection.documentStructure.length).toBe(2);
|
||||
expect(collection.documentStructure[1].id).toBe(document.id);
|
||||
expect(collection.documentStructure[1].children.length).toBe(1);
|
||||
expect(collection.documentStructure[1].children[0].id).toBe('5');
|
||||
expect(collection.documentStructure[1].children[0].id).toBe(id);
|
||||
});
|
||||
|
||||
test('should add as a child if with parent with index', async () => {
|
||||
const { collection, document } = await seed();
|
||||
const newDocument = new Document({
|
||||
id: '5',
|
||||
id: uuid.v4(),
|
||||
title: 'node',
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
const id = uuid.v4();
|
||||
const secondDocument = new Document({
|
||||
id: '6',
|
||||
id,
|
||||
title: 'New start node',
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
@@ -72,14 +77,15 @@ describe('#addDocumentToStructure', async () => {
|
||||
expect(collection.documentStructure.length).toBe(2);
|
||||
expect(collection.documentStructure[1].id).toBe(document.id);
|
||||
expect(collection.documentStructure[1].children.length).toBe(2);
|
||||
expect(collection.documentStructure[1].children[0].id).toBe('6');
|
||||
expect(collection.documentStructure[1].children[0].id).toBe(id);
|
||||
});
|
||||
|
||||
describe('options: documentJson', async () => {
|
||||
test("should append supplied json over document's own", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuid.v4();
|
||||
const newDocument = new Document({
|
||||
id: '5',
|
||||
id: uuid.v4(),
|
||||
title: 'New end node',
|
||||
parentDocumentId: null,
|
||||
});
|
||||
@@ -88,7 +94,7 @@ describe('#addDocumentToStructure', async () => {
|
||||
documentJson: {
|
||||
children: [
|
||||
{
|
||||
id: '7',
|
||||
id,
|
||||
title: 'Totally fake',
|
||||
children: [],
|
||||
},
|
||||
@@ -96,7 +102,7 @@ describe('#addDocumentToStructure', async () => {
|
||||
},
|
||||
});
|
||||
expect(collection.documentStructure[2].children.length).toBe(1);
|
||||
expect(collection.documentStructure[2].children[0].id).toBe('7');
|
||||
expect(collection.documentStructure[2].children[0].id).toBe(id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import Plain from 'slate-plain-serializer';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
import isUUID from 'validator/lib/isUUID';
|
||||
import { Collection } from '../models';
|
||||
import { DataTypes, sequelize } from '../sequelize';
|
||||
import events from '../events';
|
||||
import parseTitle from '../../shared/utils/parseTitle';
|
||||
@@ -107,6 +108,10 @@ Document.associate = models => {
|
||||
foreignKey: 'atlasId',
|
||||
onDelete: 'cascade',
|
||||
});
|
||||
Document.belongsTo(models.Team, {
|
||||
as: 'team',
|
||||
foreignKey: 'teamId',
|
||||
});
|
||||
Document.belongsTo(models.User, {
|
||||
as: 'createdBy',
|
||||
foreignKey: 'createdById',
|
||||
@@ -223,23 +228,51 @@ Document.searchForUser = async (
|
||||
|
||||
// Hooks
|
||||
|
||||
Document.addHook('afterCreate', model =>
|
||||
events.add({ name: 'documents.create', model })
|
||||
);
|
||||
Document.addHook('beforeSave', async model => {
|
||||
if (!model.publishedAt) return;
|
||||
|
||||
const collection = await Collection.findById(model.atlasId);
|
||||
if (collection.type !== 'atlas') return;
|
||||
|
||||
await collection.updateDocument(model);
|
||||
model.collection = collection;
|
||||
});
|
||||
|
||||
Document.addHook('afterCreate', async model => {
|
||||
if (!model.publishedAt) return;
|
||||
|
||||
const collection = await Collection.findById(model.atlasId);
|
||||
if (collection.type !== 'atlas') return;
|
||||
|
||||
await collection.addDocumentToStructure(model);
|
||||
model.collection = collection;
|
||||
|
||||
events.add({ name: 'documents.create', model });
|
||||
return model;
|
||||
});
|
||||
|
||||
Document.addHook('afterDestroy', model =>
|
||||
events.add({ name: 'documents.delete', model })
|
||||
);
|
||||
|
||||
Document.addHook('afterUpdate', model => {
|
||||
if (!model.previous('publishedAt') && model.publishedAt) {
|
||||
events.add({ name: 'documents.publish', model });
|
||||
}
|
||||
events.add({ name: 'documents.update', model });
|
||||
});
|
||||
|
||||
// Instance methods
|
||||
|
||||
Document.prototype.publish = async function() {
|
||||
if (this.publishedAt) return this.save();
|
||||
|
||||
const collection = await Collection.findById(this.atlasId);
|
||||
if (collection.type !== 'atlas') return this.save();
|
||||
|
||||
await collection.addDocumentToStructure(this);
|
||||
|
||||
this.publishedAt = new Date();
|
||||
await this.save();
|
||||
this.collection = collection;
|
||||
|
||||
events.add({ name: 'documents.publish', model: this });
|
||||
return this;
|
||||
};
|
||||
|
||||
Document.prototype.getTimestamp = function() {
|
||||
return Math.round(new Date(this.updatedAt).getTime() / 1000);
|
||||
};
|
||||
|
||||
35
server/models/Integration.js
Normal file
35
server/models/Integration.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// @flow
|
||||
import { DataTypes, sequelize } from '../sequelize';
|
||||
|
||||
const Integration = sequelize.define('integration', {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
primaryKey: true,
|
||||
},
|
||||
type: DataTypes.STRING,
|
||||
serviceId: DataTypes.STRING,
|
||||
settings: DataTypes.JSONB,
|
||||
events: DataTypes.ARRAY(DataTypes.STRING),
|
||||
});
|
||||
|
||||
Integration.associate = models => {
|
||||
Integration.belongsTo(models.User, {
|
||||
as: 'user',
|
||||
foreignKey: 'userId',
|
||||
});
|
||||
Integration.belongsTo(models.Team, {
|
||||
as: 'team',
|
||||
foreignKey: 'teamId',
|
||||
});
|
||||
Integration.belongsTo(models.Collection, {
|
||||
as: 'collection',
|
||||
foreignKey: 'collectionId',
|
||||
});
|
||||
Integration.belongsTo(models.Authentication, {
|
||||
as: 'authentication',
|
||||
foreignKey: 'authenticationId',
|
||||
});
|
||||
};
|
||||
|
||||
export default Integration;
|
||||
@@ -1,10 +1,11 @@
|
||||
/* eslint-disable flowtype/require-valid-file-annotation */
|
||||
import { flushdb, seed } from '../test/support';
|
||||
import { flushdb } from '../test/support';
|
||||
import { buildUser } from '../test/factories';
|
||||
|
||||
beforeEach(flushdb);
|
||||
|
||||
it('should set JWT secret and password digest', async () => {
|
||||
const { user } = await seed();
|
||||
const user = await buildUser({ password: 'test123!' });
|
||||
expect(user.passwordDigest).toBeTruthy();
|
||||
expect(user.getJwtToken()).toBeTruthy();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
import Authentication from './Authentication';
|
||||
import Integration from './Integration';
|
||||
import Event from './Event';
|
||||
import User from './User';
|
||||
import Team from './Team';
|
||||
@@ -12,6 +13,7 @@ import Star from './Star';
|
||||
|
||||
const models = {
|
||||
Authentication,
|
||||
Integration,
|
||||
Event,
|
||||
User,
|
||||
Team,
|
||||
@@ -32,6 +34,7 @@ Object.keys(models).forEach(modelName => {
|
||||
|
||||
export {
|
||||
Authentication,
|
||||
Integration,
|
||||
Event,
|
||||
User,
|
||||
Team,
|
||||
|
||||
Reference in New Issue
Block a user