1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-18 12:49:43 +02:00

feat: Webhooks configuration, all events support, refactoring

This commit is contained in:
Maksim Eltyshev 2024-06-12 00:51:36 +02:00
parent 193daf6cfb
commit 87683fe523
96 changed files with 1280 additions and 509 deletions

View file

@ -45,6 +45,15 @@ services:
# - SMTP_PASSWORD= # - SMTP_PASSWORD=
# - SMTP_FROM="Demo Demo" <demo@demo.demo> # - SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
# - SLACK_BOT_TOKEN= # - SLACK_BOT_TOKEN=
# - SLACK_CHANNEL_ID= # - SLACK_CHANNEL_ID=

View file

@ -53,6 +53,15 @@ services:
# - SMTP_PASSWORD= # - SMTP_PASSWORD=
# - SMTP_FROM="Demo Demo" <demo@demo.demo> # - SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
# - SLACK_BOT_TOKEN= # - SLACK_BOT_TOKEN=
# - SLACK_CHANNEL_ID= # - SLACK_CHANNEL_ID=
depends_on: depends_on:

View file

@ -43,12 +43,17 @@ SECRET_KEY=notsecretkey
# SMTP_PASSWORD= # SMTP_PASSWORD=
# SMTP_FROM="Demo Demo" <demo@demo.demo> # SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# WEBHOOKS='[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]'
# SLACK_BOT_TOKEN= # SLACK_BOT_TOKEN=
# SLACK_CHANNEL_ID= # SLACK_CHANNEL_ID=
# WEBHOOK_URL=
# WEBHOOK_BEARER=
## Do not edit this ## Do not edit this
TZ=UTC TZ=UTC

View file

@ -44,12 +44,12 @@ module.exports = {
async fn(inputs, exits) { async fn(inputs, exits) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { card, board } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -83,12 +83,14 @@ module.exports = {
const fileData = await sails.helpers.attachments.processUploadedFile(file); const fileData = await sails.helpers.attachments.processUploadedFile(file);
const attachment = await sails.helpers.attachments.createOne.with({ const attachment = await sails.helpers.attachments.createOne.with({
project,
board,
list,
values: { values: {
...fileData, ...fileData,
card, card,
creatorUser: currentUser, creatorUser: currentUser,
}, },
board,
requestId: inputs.requestId, requestId: inputs.requestId,
request: this.req, request: this.req,
}); });

View file

@ -33,7 +33,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.ATTACHMENT_NOT_FOUND); .intercept('pathNotFound', () => Errors.ATTACHMENT_NOT_FOUND);
let { attachment } = path; let { attachment } = path;
const { card, board } = path; const { card, list, board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: board.id, boardId: board.id,
@ -49,9 +49,12 @@ module.exports = {
} }
attachment = await sails.helpers.attachments.deleteOne.with({ attachment = await sails.helpers.attachments.deleteOne.with({
project,
board, board,
list,
card, card,
record: attachment, record: attachment,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -37,7 +37,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.ATTACHMENT_NOT_FOUND); .intercept('pathNotFound', () => Errors.ATTACHMENT_NOT_FOUND);
let { attachment } = path; let { attachment } = path;
const { board } = path; const { card, list, board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: board.id, boardId: board.id,
@ -56,8 +56,12 @@ module.exports = {
attachment = await sails.helpers.attachments.updateOne.with({ attachment = await sails.helpers.attachments.updateOne.with({
values, values,
project,
board, board,
list,
card,
record: attachment, record: attachment,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -48,14 +48,11 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board } = await sails.helpers.boards const { board, project } = await sails.helpers.boards
.getProjectPath(inputs.boardId) .getProjectPath(inputs.boardId)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND);
const isProjectManager = await sails.helpers.users.isProjectManager( const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
currentUser.id,
board.projectId,
);
if (!isProjectManager) { if (!isProjectManager) {
throw Errors.BOARD_NOT_FOUND; // Forbidden throw Errors.BOARD_NOT_FOUND; // Forbidden
@ -71,11 +68,13 @@ module.exports = {
const boardMembership = await sails.helpers.boardMemberships.createOne const boardMembership = await sails.helpers.boardMemberships.createOne
.with({ .with({
project,
values: { values: {
...values, ...values,
board, board,
user, user,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('userAlreadyBoardMember', () => Errors.USER_ALREADY_BOARD_MEMBER); .intercept('userAlreadyBoardMember', () => Errors.USER_ALREADY_BOARD_MEMBER);

View file

@ -27,7 +27,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.BOARD_MEMBERSHIP_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_MEMBERSHIP_NOT_FOUND);
let { boardMembership } = path; let { boardMembership } = path;
const { project } = path; const { board, project } = path;
if (boardMembership.userId !== currentUser.id) { if (boardMembership.userId !== currentUser.id) {
const isProjectManager = await sails.helpers.users.isProjectManager( const isProjectManager = await sails.helpers.users.isProjectManager(
@ -42,7 +42,9 @@ module.exports = {
boardMembership = await sails.helpers.boardMemberships.deleteOne.with({ boardMembership = await sails.helpers.boardMemberships.deleteOne.with({
project, project,
board,
record: boardMembership, record: boardMembership,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -35,7 +35,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.BOARD_MEMBERSHIP_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_MEMBERSHIP_NOT_FOUND);
let { boardMembership } = path; let { boardMembership } = path;
const { project } = path; const { board, project } = path;
const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
@ -47,7 +47,10 @@ module.exports = {
boardMembership = await sails.helpers.boardMemberships.updateOne.with({ boardMembership = await sails.helpers.boardMemberships.updateOne.with({
values, values,
project,
board,
record: boardMembership, record: boardMembership,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -103,7 +103,7 @@ module.exports = {
project, project,
}, },
import: boardImport, import: boardImport,
user: currentUser, actorUser: currentUser,
requestId: inputs.requestId, requestId: inputs.requestId,
request: this.req, request: this.req,
}); });

View file

@ -22,25 +22,27 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
let { board } = await sails.helpers.boards const path = await sails.helpers.boards
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND);
let { board } = path;
const { project } = path;
if (!board) { if (!board) {
throw Errors.BOARD_NOT_FOUND; throw Errors.BOARD_NOT_FOUND;
} }
const isProjectManager = await sails.helpers.users.isProjectManager( const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
currentUser.id,
board.projectId,
);
if (!isProjectManager) { if (!isProjectManager) {
throw Errors.BOARD_NOT_FOUND; // Forbidden throw Errors.BOARD_NOT_FOUND; // Forbidden
} }
board = await sails.helpers.boards.deleteOne.with({ board = await sails.helpers.boards.deleteOne.with({
project,
record: board, record: board,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -29,18 +29,18 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
let { board } = await sails.helpers.boards const path = await sails.helpers.boards
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND);
let { board } = path;
const { project } = path;
if (!board) { if (!board) {
throw Errors.BOARD_NOT_FOUND; throw Errors.BOARD_NOT_FOUND;
} }
const isProjectManager = await sails.helpers.users.isProjectManager( const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
currentUser.id,
board.projectId,
);
if (!isProjectManager) { if (!isProjectManager) {
throw Errors.BOARD_NOT_FOUND; // Forbidden throw Errors.BOARD_NOT_FOUND; // Forbidden
@ -50,7 +50,9 @@ module.exports = {
board = await sails.helpers.boards.updateOne.with({ board = await sails.helpers.boards.updateOne.with({
values, values,
project,
record: board, record: board,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -45,12 +45,12 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { card } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -64,7 +64,7 @@ module.exports = {
const label = await Label.findOne({ const label = await Label.findOne({
id: inputs.labelId, id: inputs.labelId,
boardId: card.boardId, boardId: board.id,
}); });
if (!label) { if (!label) {
@ -73,10 +73,14 @@ module.exports = {
const cardLabel = await sails.helpers.cardLabels.createOne const cardLabel = await sails.helpers.cardLabels.createOne
.with({ .with({
project,
board,
list,
values: { values: {
card, card,
label, label,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('labelAlreadyInCard', () => Errors.LABEL_ALREADY_IN_CARD); .intercept('labelAlreadyInCard', () => Errors.LABEL_ALREADY_IN_CARD);

View file

@ -39,7 +39,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
@ -66,8 +66,12 @@ module.exports = {
} }
cardLabel = await sails.helpers.cardLabels.deleteOne.with({ cardLabel = await sails.helpers.cardLabels.deleteOne.with({
project,
board, board,
list,
card,
record: cardLabel, record: cardLabel,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -45,12 +45,12 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { card, board } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -62,7 +62,7 @@ module.exports = {
throw Errors.NOT_ENOUGH_RIGHTS; throw Errors.NOT_ENOUGH_RIGHTS;
} }
const isBoardMember = await sails.helpers.users.isBoardMember(inputs.userId, card.boardId); const isBoardMember = await sails.helpers.users.isBoardMember(inputs.userId, board.id);
if (!isBoardMember) { if (!isBoardMember) {
throw Errors.USER_NOT_FOUND; throw Errors.USER_NOT_FOUND;
@ -70,11 +70,14 @@ module.exports = {
const cardMembership = await sails.helpers.cardMemberships.createOne const cardMembership = await sails.helpers.cardMemberships.createOne
.with({ .with({
project,
board,
list,
values: { values: {
card, card,
userId: inputs.userId, userId: inputs.userId,
}, },
board, actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('userAlreadyCardMember', () => Errors.USER_ALREADY_CARD_MEMBER); .intercept('userAlreadyCardMember', () => Errors.USER_ALREADY_CARD_MEMBER);

View file

@ -39,7 +39,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board, card } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
@ -66,9 +66,12 @@ module.exports = {
} }
cardMembership = await sails.helpers.cardMemberships.deleteOne.with({ cardMembership = await sails.helpers.cardMemberships.deleteOne.with({
project,
board, board,
list,
card, card,
record: cardMembership, record: cardMembership,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -78,7 +78,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board, list } = await sails.helpers.lists const { list, board, project } = await sails.helpers.lists
.getProjectPath(inputs.listId) .getProjectPath(inputs.listId)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
@ -99,6 +99,7 @@ module.exports = {
const card = await sails.helpers.cards.createOne const card = await sails.helpers.cards.createOne
.with({ .with({
project,
board, board,
values: { values: {
...values, ...values,

View file

@ -28,12 +28,15 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
let { card } = await sails.helpers.cards const path = await sails.helpers.cards
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
let { card } = path;
const { list, board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -46,8 +49,11 @@ module.exports = {
} }
card = await sails.helpers.cards.deleteOne.with({ card = await sails.helpers.cards.deleteOne.with({
project,
board,
list,
record: card, record: card,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -35,12 +35,12 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { card, list, board } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -60,6 +60,7 @@ module.exports = {
cardLabels, cardLabels,
tasks, tasks,
} = await sails.helpers.cards.duplicateOne.with({ } = await sails.helpers.cards.duplicateOne.with({
project,
board, board,
list, list,
record: card, record: card,

View file

@ -118,7 +118,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
let { card } = path; let { card } = path;
const { list, board } = path; const { list, board, project } = path;
let boardMembership = await BoardMembership.findOne({ let boardMembership = await BoardMembership.findOne({
boardId: board.id, boardId: board.id,
@ -133,9 +133,11 @@ module.exports = {
throw Errors.NOT_ENOUGH_RIGHTS; throw Errors.NOT_ENOUGH_RIGHTS;
} }
let nextProject;
let nextBoard; let nextBoard;
if (!_.isUndefined(inputs.boardId)) { if (!_.isUndefined(inputs.boardId)) {
({ board: nextBoard } = await sails.helpers.boards ({ board: nextBoard, project: nextProject } = await sails.helpers.boards
.getProjectPath(inputs.boardId) .getProjectPath(inputs.boardId)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND)); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND));
@ -177,15 +179,17 @@ module.exports = {
card = await sails.helpers.cards.updateOne card = await sails.helpers.cards.updateOne
.with({ .with({
project,
board, board,
list, list,
record: card, record: card,
values: { values: {
...values, ...values,
project: nextProject,
board: nextBoard, board: nextBoard,
list: nextList, list: nextList,
}, },
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('positionMustBeInValues', () => Errors.POSITION_MUST_BE_PRESENT) .intercept('positionMustBeInValues', () => Errors.POSITION_MUST_BE_PRESENT)

View file

@ -32,7 +32,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board, card } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
@ -55,7 +55,9 @@ module.exports = {
}; };
const action = await sails.helpers.actions.createOne.with({ const action = await sails.helpers.actions.createOne.with({
project,
board, board,
list,
values: { values: {
...values, ...values,
card, card,

View file

@ -36,7 +36,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND); .intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND);
let { action } = path; let { action } = path;
const { board, project, card } = path; const { card, list, board, project } = path;
const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
@ -60,9 +60,12 @@ module.exports = {
} }
action = await sails.helpers.actions.deleteOne.with({ action = await sails.helpers.actions.deleteOne.with({
project,
board, board,
list,
card, card,
record: action, record: action,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -40,7 +40,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND); .intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND);
let { action } = path; let { action } = path;
const { board, project, card } = path; const { card, list, board, project } = path;
const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
@ -69,9 +69,12 @@ module.exports = {
action = await sails.helpers.actions.updateOne.with({ action = await sails.helpers.actions.updateOne.with({
values, values,
card, project,
board, board,
list,
card,
record: action, record: action,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -42,7 +42,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board } = await sails.helpers.boards const { board, project } = await sails.helpers.boards
.getProjectPath(inputs.boardId) .getProjectPath(inputs.boardId)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND);
@ -62,10 +62,12 @@ module.exports = {
const values = _.pick(inputs, ['position', 'name', 'color']); const values = _.pick(inputs, ['position', 'name', 'color']);
const label = await sails.helpers.labels.createOne.with({ const label = await sails.helpers.labels.createOne.with({
project,
values: { values: {
...values, ...values,
board, board,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -28,12 +28,15 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
let { label } = await sails.helpers.labels const path = await sails.helpers.labels
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.LABEL_NOT_FOUND); .intercept('pathNotFound', () => Errors.LABEL_NOT_FOUND);
let { label } = path;
const { board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: label.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -46,7 +49,10 @@ module.exports = {
} }
label = await sails.helpers.labels.deleteOne.with({ label = await sails.helpers.labels.deleteOne.with({
project,
board,
record: label, record: label,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -40,12 +40,15 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
let { label } = await sails.helpers.labels const path = await sails.helpers.labels
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.LABEL_NOT_FOUND); .intercept('pathNotFound', () => Errors.LABEL_NOT_FOUND);
let { label } = path;
const { board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: label.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -61,7 +64,10 @@ module.exports = {
label = await sails.helpers.labels.updateOne.with({ label = await sails.helpers.labels.updateOne.with({
values, values,
project,
board,
record: label, record: label,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -36,7 +36,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { board } = await sails.helpers.boards const { board, project } = await sails.helpers.boards
.getProjectPath(inputs.boardId) .getProjectPath(inputs.boardId)
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND);
@ -56,10 +56,12 @@ module.exports = {
const values = _.pick(inputs, ['position', 'name']); const values = _.pick(inputs, ['position', 'name']);
const list = await sails.helpers.lists.createOne.with({ const list = await sails.helpers.lists.createOne.with({
project,
values: { values: {
...values, ...values,
board, board,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -28,13 +28,15 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
// eslint-disable-next-line prefer-const const path = await sails.helpers.lists
let { list, board } = await sails.helpers.lists
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
let { list } = path;
const { board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: list.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -47,8 +49,10 @@ module.exports = {
} }
list = await sails.helpers.lists.deleteOne.with({ list = await sails.helpers.lists.deleteOne.with({
record: list, project,
board, board,
record: list,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -32,12 +32,12 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { list } = await sails.helpers.lists const { list, board, project } = await sails.helpers.lists
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: list.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -50,8 +50,11 @@ module.exports = {
} }
const cards = await sails.helpers.lists.sortOne.with({ const cards = await sails.helpers.lists.sortOne.with({
project,
board,
record: list, record: list,
type: inputs.type, type: inputs.type,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -35,13 +35,15 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
// eslint-disable-next-line prefer-const const path = await sails.helpers.lists
let { list, board } = await sails.helpers.lists
.getProjectPath(inputs.id) .getProjectPath(inputs.id)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
let { list } = path;
const { board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: list.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -57,8 +59,10 @@ module.exports = {
list = await sails.helpers.lists.updateOne.with({ list = await sails.helpers.lists.updateOne.with({
values, values,
project,
board, board,
record: list, record: list,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -18,7 +18,7 @@ module.exports = {
const notifications = await sails.helpers.notifications.updateMany.with({ const notifications = await sails.helpers.notifications.updateMany.with({
values, values,
recordsOrIds: inputs.ids.split(','), recordsOrIds: inputs.ids.split(','),
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -63,6 +63,7 @@ module.exports = {
project, project,
user, user,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('userAlreadyProjectManager', () => Errors.USER_ALREADY_PROJECT_MANAGER); .intercept('userAlreadyProjectManager', () => Errors.USER_ALREADY_PROJECT_MANAGER);

View file

@ -40,6 +40,7 @@ module.exports = {
// TODO: check if the last one // TODO: check if the last one
projectManager = await sails.helpers.projectManagers.deleteOne.with({ projectManager = await sails.helpers.projectManagers.deleteOne.with({
record: projectManager, record: projectManager,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -13,7 +13,7 @@ module.exports = {
const { project, projectManager } = await sails.helpers.projects.createOne.with({ const { project, projectManager } = await sails.helpers.projects.createOne.with({
values, values,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -36,6 +36,7 @@ module.exports = {
project = await sails.helpers.projects.deleteOne.with({ project = await sails.helpers.projects.deleteOne.with({
record: project, record: project,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -90,6 +90,7 @@ module.exports = {
values: { values: {
backgroundImage: fileData, backgroundImage: fileData,
}, },
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -81,6 +81,7 @@ module.exports = {
project = await sails.helpers.projects.updateOne.with({ project = await sails.helpers.projects.updateOne.with({
values, values,
record: project, record: project,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -39,12 +39,12 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req; const { currentUser } = this.req;
const { card, board } = await sails.helpers.cards const { card, list, board, project } = await sails.helpers.cards
.getProjectPath(inputs.cardId) .getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: card.boardId, boardId: board.id,
userId: currentUser.id, userId: currentUser.id,
}); });
@ -59,11 +59,14 @@ module.exports = {
const values = _.pick(inputs, ['position', 'name', 'isCompleted']); const values = _.pick(inputs, ['position', 'name', 'isCompleted']);
const task = await sails.helpers.tasks.createOne.with({ const task = await sails.helpers.tasks.createOne.with({
project,
board,
list,
values: { values: {
...values, ...values,
card, card,
}, },
board, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -33,7 +33,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.TASK_NOT_FOUND); .intercept('pathNotFound', () => Errors.TASK_NOT_FOUND);
let { task } = path; let { task } = path;
const { board } = path; const { card, list, board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: board.id, boardId: board.id,
@ -49,8 +49,12 @@ module.exports = {
} }
task = await sails.helpers.tasks.deleteOne.with({ task = await sails.helpers.tasks.deleteOne.with({
project,
board, board,
list,
card,
record: task, record: task,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -43,7 +43,7 @@ module.exports = {
.intercept('pathNotFound', () => Errors.TASK_NOT_FOUND); .intercept('pathNotFound', () => Errors.TASK_NOT_FOUND);
let { task } = path; let { task } = path;
const { board } = path; const { card, list, board, project } = path;
const boardMembership = await BoardMembership.findOne({ const boardMembership = await BoardMembership.findOne({
boardId: board.id, boardId: board.id,
@ -62,8 +62,12 @@ module.exports = {
task = await sails.helpers.tasks.updateOne.with({ task = await sails.helpers.tasks.updateOne.with({
values, values,
project,
board, board,
list,
card,
record: task, record: task,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -71,6 +71,8 @@ module.exports = {
}, },
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req;
if (sails.config.custom.oidcEnforced) { if (sails.config.custom.oidcEnforced) {
throw Errors.NOT_ENOUGH_RIGHTS; throw Errors.NOT_ENOUGH_RIGHTS;
} }
@ -89,6 +91,7 @@ module.exports = {
const user = await sails.helpers.users.createOne const user = await sails.helpers.users.createOne
.with({ .with({
values, values,
actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE) .intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE)

View file

@ -26,6 +26,8 @@ module.exports = {
}, },
async fn(inputs) { async fn(inputs) {
const { currentUser } = this.req;
let user = await sails.helpers.users.getOne(inputs.id); let user = await sails.helpers.users.getOne(inputs.id);
if (!user) { if (!user) {
@ -38,6 +40,7 @@ module.exports = {
user = await sails.helpers.users.deleteOne.with({ user = await sails.helpers.users.deleteOne.with({
record: user, record: user,
actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -91,7 +91,7 @@ module.exports = {
values: { values: {
avatar: fileData, avatar: fileData,
}, },
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -82,7 +82,7 @@ module.exports = {
.with({ .with({
values, values,
record: user, record: user,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE); .intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE);

View file

@ -80,7 +80,7 @@ module.exports = {
user = await sails.helpers.users.updateOne.with({ user = await sails.helpers.users.updateOne.with({
values, values,
record: user, record: user,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -83,7 +83,7 @@ module.exports = {
.with({ .with({
values, values,
record: user, record: user,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}) })
.intercept('usernameAlreadyInUse', () => Errors.USERNAME_ALREADY_IN_USE); .intercept('usernameAlreadyInUse', () => Errors.USERNAME_ALREADY_IN_USE);

View file

@ -95,7 +95,7 @@ module.exports = {
user = await sails.helpers.users.updateOne.with({ user = await sails.helpers.users.updateOne.with({
values, values,
record: user, record: user,
user: currentUser, actorUser: currentUser,
request: this.req, request: this.req,
}); });

View file

@ -14,21 +14,21 @@ const valuesValidator = (value) => {
return true; return true;
}; };
const buildAndSendSlackMessage = async (user, card, action) => { const buildAndSendSlackMessage = async (card, action, actorUser) => {
const cardLink = `<${sails.config.custom.baseUrl}/cards/${card.id}|${card.name}>`; const cardLink = `<${sails.config.custom.baseUrl}/cards/${card.id}|${card.name}>`;
let markdown; let markdown;
switch (action.type) { switch (action.type) {
case Action.Types.CREATE_CARD: case Action.Types.CREATE_CARD:
markdown = `${cardLink} was created by ${user.name} in *${action.data.list.name}*`; markdown = `${cardLink} was created by ${actorUser.name} in *${action.data.list.name}*`;
break; break;
case Action.Types.MOVE_CARD: case Action.Types.MOVE_CARD:
markdown = `${cardLink} was moved by ${user.name} to *${action.data.toList.name}*`; markdown = `${cardLink} was moved by ${actorUser.name} to *${action.data.toList.name}*`;
break; break;
case Action.Types.COMMENT_CARD: case Action.Types.COMMENT_CARD:
markdown = `*${user.name}* commented on ${cardLink}:\n>${action.data.text}`; markdown = `*${actorUser.name}* commented on ${cardLink}:\n>${action.data.text}`;
break; break;
default: default:
@ -45,10 +45,18 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -72,6 +80,24 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'actionCreate',
data: {
item: action,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [values.card],
},
},
user: values.user,
});
if (sails.config.custom.slackBotToken) {
buildAndSendSlackMessage(values.card, action, values.user);
}
const subscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds( const subscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds(
action.cardId, action.cardId,
action.userId, action.userId,
@ -84,26 +110,15 @@ module.exports = {
userId, userId,
action, action,
}, },
user: values.user, project: inputs.project,
board: inputs.board, board: inputs.board,
list: inputs.list,
card: values.card, card: values.card,
actorUser: values.user,
}), }),
), ),
); );
if (sails.config.custom.slackBotToken) {
buildAndSendSlackMessage(values.user, values.card, action);
}
await sails.helpers.utils.sendWebhook.with({
event: 'ACTION_CREATE',
data: action,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card: values.card,
board: inputs.board,
});
return action; return action;
}, },
}; };

View file

@ -4,11 +4,23 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
list: {
type: 'ref',
required: true,
},
card: { card: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
board: { actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -30,13 +42,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'ACTION_DELETE', event: 'actionDelete',
data: action, data: {
projectId: inputs.board.projectId, item: action,
user: inputs.request.currentUser, included: {
card: inputs.card, projects: [inputs.project],
board: inputs.board, boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -8,7 +8,7 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
card: { project: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -16,6 +16,18 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -36,13 +48,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'ACTION_UPDATE', event: 'actionUpdate',
data: action, data: {
projectId: inputs.board.projectId, item: action,
user: inputs.request.currentUser, included: {
card: inputs.card, projects: [inputs.project],
board: inputs.board, boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -21,10 +21,18 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
requestId: { requestId: {
type: 'string', type: 'string',
isNotEmptyString: true, isNotEmptyString: true,
@ -35,7 +43,7 @@ module.exports = {
}, },
async fn(inputs) { async fn(inputs) {
const { values, board } = inputs; const { values } = inputs;
const attachment = await Attachment.create({ const attachment = await Attachment.create({
...values, ...values,
@ -53,26 +61,33 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'attachmentCreate',
data: {
item: attachment,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [values.card],
},
},
user: values.creatorUser,
});
if (!values.card.coverAttachmentId && attachment.image) { if (!values.card.coverAttachmentId && attachment.image) {
await sails.helpers.cards.updateOne.with({ await sails.helpers.cards.updateOne.with({
record: values.card, record: values.card,
values: { values: {
coverAttachmentId: attachment.id, coverAttachmentId: attachment.id,
}, },
board, project: inputs.project,
request: inputs.request, board: inputs.board,
list: inputs.list,
actorUser: values.creatorUser,
}); });
} }
await sails.helpers.utils.sendWebhook.with({
event: 'ATTACHMENT_CREATE',
data: attachment,
projectId: board.projectId,
user: inputs.request.currentUser,
card: values.card,
board,
});
return attachment; return attachment;
}, },
}; };

View file

@ -7,14 +7,26 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: { card: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -27,6 +39,10 @@ module.exports = {
values: { values: {
coverAttachmentId: null, coverAttachmentId: null,
}, },
project: inputs.project,
board: inputs.board,
list: inputs.list,
actorUser: inputs.actorUser,
request: inputs.request, request: inputs.request,
}); });
} }
@ -49,13 +65,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'ATTACHMENT_DELETE', event: 'attachmentDelete',
data: attachment, data: {
projectId: inputs.board.projectId, item: attachment,
user: inputs.request.currentUser, included: {
card: inputs.card, projects: [inputs.project],
board: inputs.board, boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -8,10 +8,26 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -32,12 +48,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'ATTACHMENT_UPDATE', event: 'attachmentUpdate',
data: attachment, data: {
projectId: inputs.board.projectId, item: attachment,
user: inputs.request.currentUser, included: {
board: inputs.board, projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -21,6 +21,14 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -67,6 +75,19 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipCreate',
data: {
item: boardMembership,
included: {
users: [values.user],
projects: [inputs.project],
boards: [values.board],
},
},
user: inputs.actorUser,
});
return boardMembership; return boardMembership;
}, },
}; };

View file

@ -10,6 +10,14 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
board: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -73,6 +81,18 @@ module.exports = {
); );
}); });
} }
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipDelete',
data: {
item: boardMembership,
included: {
projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
});
} }
return boardMembership; return boardMembership;

View file

@ -8,6 +8,18 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -40,6 +52,18 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'boardMembershipUpdate',
data: {
item: boardMembership,
included: {
projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
});
} }
return boardMembership; return boardMembership;

View file

@ -37,7 +37,7 @@ module.exports = {
type: 'json', type: 'json',
custom: importValidator, custom: importValidator,
}, },
user: { actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -80,6 +80,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
}); });
@ -90,12 +92,12 @@ module.exports = {
}).fetch(); }).fetch();
if (inputs.import && inputs.import.type === Board.ImportTypes.TRELLO) { if (inputs.import && inputs.import.type === Board.ImportTypes.TRELLO) {
await sails.helpers.boards.importFromTrello(inputs.user, board, inputs.import.board); await sails.helpers.boards.importFromTrello(board, inputs.import.board, inputs.actorUser);
} }
const boardMembership = await BoardMembership.create({ const boardMembership = await BoardMembership.create({
boardId: board.id, boardId: board.id,
userId: inputs.user.id, userId: inputs.actorUser.id,
role: BoardMembership.Roles.EDITOR, role: BoardMembership.Roles.EDITOR,
}).fetch(); }).fetch();
@ -111,12 +113,15 @@ module.exports = {
); );
}); });
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'BOARD_CREATE', event: 'boardCreate',
data: board, data: {
projectId: board.projectId, item: board,
user: inputs.request.currentUser, included: {
board, projects: [values.project],
},
},
user: inputs.actorUser,
}); });
return { return {

View file

@ -4,6 +4,14 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -33,15 +41,18 @@ module.exports = {
inputs.request, inputs.request,
); );
}); });
}
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'BOARD_DELETE', event: 'boardDelete',
data: board, data: {
projectId: board.projectId, item: board,
user: inputs.request.currentUser, included: {
board, projects: [inputs.project],
}); },
},
user: inputs.actorUser,
});
}
return board; return board;
}, },

View file

@ -2,10 +2,6 @@ const POSITION_GAP = 65535; // TODO: move to config
module.exports = { module.exports = {
inputs: { inputs: {
user: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
@ -14,6 +10,10 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
}, },
async fn(inputs) { async fn(inputs) {
@ -87,7 +87,7 @@ module.exports = {
trelloComments.map(async (trelloComment) => { trelloComments.map(async (trelloComment) => {
return Action.create({ return Action.create({
cardId: plankaCard.id, cardId: plankaCard.id,
userId: inputs.user.id, userId: inputs.actorUser.id,
type: 'commentCard', type: 'commentCard',
data: { data: {
text: text:
@ -105,7 +105,7 @@ module.exports = {
const plankaCard = await Card.create({ const plankaCard = await Card.create({
boardId: inputs.board.id, boardId: inputs.board.id,
listId: plankaList.id, listId: plankaList.id,
creatorUserId: inputs.user.id, creatorUserId: inputs.actorUser.id,
position: trelloCard.pos, position: trelloCard.pos,
name: trelloCard.name, name: trelloCard.name,
description: trelloCard.desc || null, description: trelloCard.desc || null,

View file

@ -21,6 +21,14 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -64,6 +72,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
}); });
} }
@ -81,15 +91,18 @@ module.exports = {
inputs.request, inputs.request,
); );
}); });
}
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'BOARD_UPDATE', event: 'boardUpdate',
data: board, data: {
projectId: board.projectId, item: board,
user: inputs.request.currentUser, included: {
board, projects: [inputs.project],
}); },
},
user: inputs.actorUser,
});
}
return board; return board;
}, },

View file

@ -21,6 +21,22 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
list: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -50,6 +66,21 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardLabelCreate',
data: {
item: cardLabel,
included: {
projects: [inputs.project],
boards: [inputs.board],
labels: [values.label],
lists: [inputs.list],
cards: [values.card],
},
},
user: inputs.actorUser,
});
return cardLabel; return cardLabel;
}, },
}; };

View file

@ -4,10 +4,26 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -25,6 +41,20 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardLabelDelete',
data: {
item: cardLabel,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
});
} }
return cardLabel; return cardLabel;

View file

@ -21,10 +21,22 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -57,6 +69,20 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardMembershipCreate',
data: {
item: cardMembership,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [values.card],
},
},
user: inputs.actorUser,
});
const cardSubscription = await CardSubscription.create({ const cardSubscription = await CardSubscription.create({
cardId: cardMembership.cardId, cardId: cardMembership.cardId,
userId: cardMembership.userId, userId: cardMembership.userId,
@ -77,16 +103,9 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
}
await sails.helpers.utils.sendWebhook.with({ // TODO: send webhooks
event: 'CARD_MEMBERSHIP_CREATE', }
data: cardMembership,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card: values.card,
board: inputs.board,
});
return cardMembership; return cardMembership;
}, },

View file

@ -4,11 +4,23 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
list: {
type: 'ref',
required: true,
},
card: { card: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
board: { actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -30,6 +42,20 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardMembershipDelete',
data: {
item: cardMembership,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
});
const cardSubscription = await CardSubscription.destroyOne({ const cardSubscription = await CardSubscription.destroyOne({
cardId: cardMembership.cardId, cardId: cardMembership.cardId,
userId: cardMembership.userId, userId: cardMembership.userId,
@ -43,16 +69,9 @@ module.exports = {
isSubscribed: false, isSubscribed: false,
}, },
}); });
}
await sails.helpers.utils.sendWebhook.with({ // TODO: send webhook
event: 'CARD_MEMBERSHIP_DELETE', }
data: cardMembership,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card: inputs.card,
board: inputs.board,
});
} }
return cardMembership; return cardMembership;

View file

@ -25,6 +25,10 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
@ -66,6 +70,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
const card = await Card.create({ const card = await Card.create({
@ -85,6 +91,19 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardCreate',
data: {
item: card,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [values.list],
},
},
user: values.creatorUser,
});
if (values.creatorUser.subscribeToOwnCards) { if (values.creatorUser.subscribeToOwnCards) {
await CardSubscription.create({ await CardSubscription.create({
cardId: card.id, cardId: card.id,
@ -97,6 +116,8 @@ module.exports = {
isSubscribed: true, isSubscribed: true,
}, },
}); });
// TODO: send webhooks
} }
await sails.helpers.actions.createOne.with({ await sails.helpers.actions.createOne.with({
@ -108,18 +129,10 @@ module.exports = {
}, },
user: values.creatorUser, user: values.creatorUser,
}, },
board: inputs.board, project: inputs.project,
request: inputs.request,
});
await sails.helpers.utils.sendWebhook.with({
event: 'CARD_CREATE',
data: card,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card,
board: inputs.board, board: inputs.board,
list: values.list, list: values.list,
request: inputs.request,
}); });
return card; return card;

View file

@ -1,5 +1,5 @@
const buildAndSendSlackMessage = async (user, card) => { const buildAndSendSlackMessage = async (card, actorUser) => {
await sails.helpers.utils.sendSlackMessage(`*${card.name}* was deleted by ${user.name}`); await sails.helpers.utils.sendSlackMessage(`*${card.name}* was deleted by ${actorUser.name}`);
}; };
module.exports = { module.exports = {
@ -8,7 +8,19 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
user: { project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
list: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -21,10 +33,6 @@ module.exports = {
const card = await Card.archiveOne(inputs.record.id); const card = await Card.archiveOne(inputs.record.id);
if (card) { if (card) {
const { board } = await sails.helpers.lists
.getProjectPath(card.listId)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
sails.sockets.broadcast( sails.sockets.broadcast(
`board:${card.boardId}`, `board:${card.boardId}`,
'cardDelete', 'cardDelete',
@ -34,18 +42,22 @@ module.exports = {
inputs.request, inputs.request,
); );
if (sails.config.custom.slackBotToken) { sails.helpers.utils.sendWebhooks.with({
buildAndSendSlackMessage(inputs.user, card); event: 'cardDelete',
} data: {
item: card,
await sails.helpers.utils.sendWebhook.with({ included: {
event: 'CARD_DELETE', projects: [inputs.project],
data: card, boards: [inputs.board],
projectId: board.projectId, lists: [inputs.list],
user: inputs.request.currentUser, },
card, },
board, user: inputs.actorUser,
}); });
if (sails.config.custom.slackBotToken) {
buildAndSendSlackMessage(card, inputs.actorUser);
}
} }
return card; return card;

View file

@ -25,6 +25,10 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
@ -62,6 +66,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
const card = await Card.create({ const card = await Card.create({
@ -108,6 +114,19 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'cardCreate',
data: {
item: card,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
},
},
user: values.creatorUser,
});
if (values.creatorUser.subscribeToOwnCards) { if (values.creatorUser.subscribeToOwnCards) {
await CardSubscription.create({ await CardSubscription.create({
cardId: card.id, cardId: card.id,
@ -120,6 +139,8 @@ module.exports = {
isSubscribed: true, isSubscribed: true,
}, },
}); });
// TODO: send webhooks
} }
await sails.helpers.actions.createOne.with({ await sails.helpers.actions.createOne.with({
@ -131,18 +152,10 @@ module.exports = {
}, },
user: values.creatorUser, user: values.creatorUser,
}, },
board: inputs.board, project: inputs.project,
request: inputs.request,
});
await sails.helpers.utils.sendWebhook.with({
event: 'CARD_CREATE',
data: card,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card,
board: inputs.board, board: inputs.board,
list: inputs.list, list: inputs.list,
request: inputs.request,
}); });
return { return {

View file

@ -7,8 +7,14 @@ const valuesValidator = (value) => {
return false; return false;
} }
if (!_.isUndefined(value.board) && !_.isPlainObject(value.board)) { if (!_.isUndefined(value.board)) {
return false; if (!_.isPlainObject(value.project)) {
return false;
}
if (!_.isPlainObject(value.board)) {
return false;
}
} }
if (!_.isUndefined(value.list) && !_.isPlainObject(value.list)) { if (!_.isUndefined(value.list) && !_.isPlainObject(value.list)) {
@ -29,14 +35,21 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
user: { project: {
type: 'ref', type: 'ref',
required: true,
}, },
board: { board: {
type: 'ref', type: 'ref',
required: true,
}, },
list: { list: {
type: 'ref', type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
}, },
request: { request: {
type: 'ref', type: 'ref',
@ -45,65 +58,56 @@ module.exports = {
exits: { exits: {
positionMustBeInValues: {}, positionMustBeInValues: {},
boardInValuesMustBelongToProject: {},
listMustBeInValues: {}, listMustBeInValues: {},
listInValuesMustBelongToBoard: {}, listInValuesMustBelongToBoard: {},
userMustBePresent: {},
boardMustBePresent: {},
listMustBePresent: {},
}, },
async fn(inputs) { async fn(inputs) {
const { isSubscribed, ...values } = inputs.values; const { isSubscribed, ...values } = inputs.values;
if (values.board || values.list || !_.isUndefined(values.position)) { if (values.project && values.project.id === inputs.project.id) {
if (!inputs.board) { delete values.project;
throw 'boardMustBePresent'; }
const project = values.project || inputs.project;
if (values.board) {
if (values.board.projectId !== project.id) {
throw 'boardInValuesMustBelongToProject';
} }
if (values.board) { if (values.board.id === inputs.board.id) {
if (values.board.id === inputs.board.id) { delete values.board;
delete values.board; } else {
} else { values.boardId = values.board.id;
values.boardId = values.board.id;
}
}
const board = values.board || inputs.board;
if (values.list) {
if (!inputs.list) {
throw 'listMustBePresent';
}
if (values.list.boardId !== board.id) {
throw 'listInValuesMustBelongToBoard';
}
if (values.list.id === inputs.list.id) {
delete values.list;
} else {
values.listId = values.list.id;
}
}
if (values.list) {
if (_.isUndefined(values.position)) {
throw 'positionMustBeInValues';
}
} else if (values.board) {
throw 'listMustBeInValues';
} }
} }
if ((!_.isUndefined(isSubscribed) || values.board || values.list) && !inputs.user) { const board = values.board || inputs.board;
throw 'userMustBePresent';
if (values.list) {
if (values.list.boardId !== board.id) {
throw 'listInValuesMustBelongToBoard';
}
if (values.list.id === inputs.list.id) {
delete values.list;
} else {
values.listId = values.list.id;
}
} else if (values.board) {
throw 'listMustBeInValues';
}
const list = values.list || inputs.list;
if (values.list && _.isUndefined(values.position)) {
throw 'positionMustBeInValues';
} }
if (!_.isUndefined(values.position)) { if (!_.isUndefined(values.position)) {
const boardId = values.boardId || inputs.record.boardId; const cards = await sails.helpers.lists.getCards(list.id, inputs.record.id);
const listId = values.listId || inputs.record.listId;
const cards = await sails.helpers.lists.getCards(listId, inputs.record.id);
const { position, repositions } = sails.helpers.utils.insertToPositionables( const { position, repositions } = sails.helpers.utils.insertToPositionables(
values.position, values.position,
@ -115,17 +119,19 @@ module.exports = {
repositions.forEach(async ({ id, position: nextPosition }) => { repositions.forEach(async ({ id, position: nextPosition }) => {
await Card.update({ await Card.update({
id, id,
listId, listId: list.id,
}).set({ }).set({
position: nextPosition, position: nextPosition,
}); });
sails.sockets.broadcast(`board:${boardId}`, 'cardUpdate', { sails.sockets.broadcast(`board:${board.id}`, 'cardUpdate', {
item: { item: {
id, id,
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
} }
@ -175,10 +181,12 @@ module.exports = {
} }
const { id } = await sails.helpers.labels.createOne.with({ const { id } = await sails.helpers.labels.createOne.with({
project,
values: { values: {
..._.omit(label, ['id', 'boardId']), ..._.omit(label, ['id', 'boardId']),
board: values.board, board: values.board,
}, },
actorUser: inputs.actorUser,
}); });
return id; return id;
@ -209,6 +217,8 @@ module.exports = {
isSubscribed: true, isSubscribed: true,
}, },
}); });
// TODO: send webhooks
}); });
} else { } else {
sails.sockets.broadcast( sails.sockets.broadcast(
@ -221,18 +231,33 @@ module.exports = {
); );
} }
sails.helpers.utils.sendWebhooks.with({
event: 'cardUpdate',
data: {
item: card,
included: {
projects: [project],
boards: [board],
lists: [list],
},
},
user: inputs.actorUser,
});
if (!values.board && values.list) { if (!values.board && values.list) {
await sails.helpers.actions.createOne.with({ await sails.helpers.actions.createOne.with({
project,
board,
list,
values: { values: {
card, card,
user: inputs.user, user: inputs.actorUser,
type: Action.Types.MOVE_CARD, type: Action.Types.MOVE_CARD,
data: { data: {
fromList: _.pick(inputs.list, ['id', 'name']), fromList: _.pick(inputs.list, ['id', 'name']),
toList: _.pick(values.list, ['id', 'name']), toList: _.pick(values.list, ['id', 'name']),
}, },
}, },
board: inputs.board,
request: inputs.request, request: inputs.request,
}); });
} }
@ -241,23 +266,26 @@ module.exports = {
} }
if (!_.isUndefined(isSubscribed)) { if (!_.isUndefined(isSubscribed)) {
const prevIsSubscribed = await sails.helpers.users.isCardSubscriber(inputs.user.id, card.id); const prevIsSubscribed = await sails.helpers.users.isCardSubscriber(
inputs.actorUser.id,
card.id,
);
if (isSubscribed !== prevIsSubscribed) { if (isSubscribed !== prevIsSubscribed) {
if (isSubscribed) { if (isSubscribed) {
await CardSubscription.create({ await CardSubscription.create({
cardId: card.id, cardId: card.id,
userId: inputs.user.id, userId: inputs.actorUser.id,
}).tolerate('E_UNIQUE'); }).tolerate('E_UNIQUE');
} else { } else {
await CardSubscription.destroyOne({ await CardSubscription.destroyOne({
cardId: card.id, cardId: card.id,
userId: inputs.user.id, userId: inputs.actorUser.id,
}); });
} }
sails.sockets.broadcast( sails.sockets.broadcast(
`user:${inputs.user.id}`, `user:${inputs.actorUser.id}`,
'cardUpdate', 'cardUpdate',
{ {
item: { item: {
@ -267,18 +295,11 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
// TODO: send webhooks
} }
} }
await sails.helpers.utils.sendWebhook.with({
event: 'CARD_UPDATE',
data: card,
projectId: inputs.board.projectId,
user: inputs.request.currentUser,
card,
board: inputs.board,
});
return card; return card;
}, },
}; };

View file

@ -21,6 +21,14 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -50,6 +58,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
const label = await Label.create({ const label = await Label.create({
@ -67,6 +77,18 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'labelCreate',
data: {
item: label,
included: {
projects: [inputs.project],
boards: [values.board],
},
},
user: inputs.actorUser,
});
return label; return label;
}, },
}; };

View file

@ -4,6 +4,18 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -25,6 +37,18 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'labelDelete',
data: {
item: label,
included: {
projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
});
} }
return label; return label;

View file

@ -21,6 +21,18 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -53,6 +65,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
} }
@ -67,6 +81,18 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'labelUpdate',
data: {
item: label,
included: {
projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
});
} }
return label; return label;

View file

@ -21,6 +21,14 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -50,6 +58,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
const list = await List.create({ const list = await List.create({
@ -67,12 +77,16 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'LIST_CREATE', event: 'listCreate',
data: list, data: {
projectId: values.board.projectId, item: list,
user: inputs.request.currentUser, included: {
board: values.board, projects: [inputs.project],
boards: [values.board],
},
},
user: inputs.actorUser,
}); });
return list; return list;

View file

@ -4,10 +4,18 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -26,12 +34,16 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'LIST_DELETE', event: 'listDelete',
data: list, data: {
projectId: inputs.board.projectId, item: list,
user: inputs.request.currentUser, included: {
board: inputs.board, projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -11,6 +11,18 @@ module.exports = {
isIn: Object.values(List.SortTypes), isIn: Object.values(List.SortTypes),
defaultsTo: List.SortTypes.NAME_ASC, defaultsTo: List.SortTypes.NAME_ASC,
}, },
project: {
type: 'ref',
required: true,
},
board: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -65,6 +77,19 @@ module.exports = {
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'listSort',
data: {
item: inputs.record,
included: {
cards,
projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
});
return cards; return cards;
}, },
}; };

View file

@ -21,10 +21,18 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -57,6 +65,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
} }
@ -72,12 +82,16 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'LIST_UPDATE', event: 'listUpdate',
data: list, data: {
projectId: inputs.board.projectId, item: list,
user: inputs.request.currentUser, included: {
board: inputs.board, projects: [inputs.project],
boards: [inputs.board],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -15,14 +15,14 @@ const valuesValidator = (value) => {
}; };
// TODO: use templates (views) to build html // TODO: use templates (views) to build html
const buildAndSendEmail = async (user, board, card, action, notifiableUser) => { const buildAndSendEmail = async (board, card, action, actorUser, notifiableUser) => {
let emailData; let emailData;
switch (action.type) { switch (action.type) {
case Action.Types.MOVE_CARD: case Action.Types.MOVE_CARD:
emailData = { emailData = {
subject: `${user.name} moved ${card.name} from ${action.data.fromList.name} to ${action.data.toList.name} on ${board.name}`, subject: `${actorUser.name} moved ${card.name} from ${action.data.fromList.name} to ${action.data.toList.name} on ${board.name}`,
html: html:
`<p>${user.name} moved ` + `<p>${actorUser.name} moved ` +
`<a href="${process.env.BASE_URL}/cards/${card.id}">${card.name}</a> ` + `<a href="${process.env.BASE_URL}/cards/${card.id}">${card.name}</a> ` +
`from ${action.data.fromList.name} to ${action.data.toList.name} ` + `from ${action.data.fromList.name} to ${action.data.toList.name} ` +
`on <a href="${process.env.BASE_URL}/boards/${board.id}">${board.name}</a></p>`, `on <a href="${process.env.BASE_URL}/boards/${board.id}">${board.name}</a></p>`,
@ -31,9 +31,9 @@ const buildAndSendEmail = async (user, board, card, action, notifiableUser) => {
break; break;
case Action.Types.COMMENT_CARD: case Action.Types.COMMENT_CARD:
emailData = { emailData = {
subject: `${user.name} left a new comment to ${card.name} on ${board.name}`, subject: `${actorUser.name} left a new comment to ${card.name} on ${board.name}`,
html: html:
`<p>${user.name} left a new comment to ` + `<p>${actorUser.name} left a new comment to ` +
`<a href="${process.env.BASE_URL}/cards/${card.id}">${card.name}</a> ` + `<a href="${process.env.BASE_URL}/cards/${card.id}">${card.name}</a> ` +
`on <a href="${process.env.BASE_URL}/boards/${board.id}">${board.name}</a></p>` + `on <a href="${process.env.BASE_URL}/boards/${board.id}">${board.name}</a></p>` +
`<p>${action.data.text}</p>`, `<p>${action.data.text}</p>`,
@ -57,7 +57,7 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
user: { project: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -65,10 +65,18 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: { card: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
}, },
async fn(inputs) { async fn(inputs) {
@ -96,9 +104,24 @@ module.exports = {
notifiableUser = await sails.helpers.users.getOne(notification.userId); notifiableUser = await sails.helpers.users.getOne(notification.userId);
} }
buildAndSendEmail(inputs.user, inputs.board, inputs.card, values.action, notifiableUser); buildAndSendEmail(inputs.board, inputs.card, values.action, inputs.actorUser, notifiableUser);
} }
sails.helpers.utils.sendWebhooks.with({
event: 'notificationCreate',
data: {
item: notification,
included: {
projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
actions: [values.action],
},
},
user: inputs.actorUser,
});
return notification; return notification;
}, },
}; };

View file

@ -12,8 +12,9 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
user: { actorUser: {
type: 'ref', type: 'ref',
required: true,
}, },
request: { request: {
type: 'ref', type: 'ref',
@ -23,7 +24,9 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
const { values } = inputs; const { values } = inputs;
const criteria = {}; const criteria = {
userId: inputs.actorUser.id,
};
if (_.every(inputs.recordsOrIds, _.isPlainObject)) { if (_.every(inputs.recordsOrIds, _.isPlainObject)) {
criteria.id = sails.helpers.utils.mapRecords(inputs.recordsOrIds); criteria.id = sails.helpers.utils.mapRecords(inputs.recordsOrIds);
@ -31,10 +34,6 @@ module.exports = {
criteria.id = inputs.recordsOrIds; criteria.id = inputs.recordsOrIds;
} }
if (inputs.user) {
criteria.userId = inputs.user.id;
}
const notifications = await Notification.update(criteria) const notifications = await Notification.update(criteria)
.set({ ...values }) .set({ ...values })
.fetch(); .fetch();
@ -48,6 +47,14 @@ module.exports = {
}, },
inputs.request, inputs.request,
); );
sails.helpers.utils.sendWebhooks.with({
event: 'notificationUpdate',
data: {
item: notification,
},
user: inputs.actorUser,
});
}); });
return notifications; return notifications;

View file

@ -21,6 +21,10 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -55,6 +59,18 @@ module.exports = {
); );
}); });
sails.helpers.utils.sendWebhooks.with({
event: 'projectManagerCreate',
data: {
item: projectManager,
included: {
users: [values.user],
projects: [values.project],
},
},
user: inputs.actorUser,
});
return projectManager; return projectManager;
}, },
}; };

View file

@ -4,6 +4,10 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -27,6 +31,14 @@ module.exports = {
inputs.request, inputs.request,
); );
}); });
sails.helpers.utils.sendWebhooks.with({
event: 'projectManagerDelete',
data: {
item: projectManager,
},
user: inputs.actorUser,
});
} }
return projectManager; return projectManager;

View file

@ -4,7 +4,7 @@ module.exports = {
type: 'json', type: 'json',
required: true, required: true,
}, },
user: { actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -20,7 +20,7 @@ module.exports = {
const projectManager = await ProjectManager.create({ const projectManager = await ProjectManager.create({
projectId: project.id, projectId: project.id,
userId: inputs.user.id, userId: inputs.actorUser.id,
}).fetch(); }).fetch();
sails.sockets.broadcast( sails.sockets.broadcast(
@ -32,11 +32,12 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'PROJECT_CREATE', event: 'projectCreate',
data: project, data: {
projectId: project.id, item: project,
user: inputs.request.currentUser, },
user: inputs.actorUser,
}); });
return { return {

View file

@ -4,6 +4,10 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -38,11 +42,12 @@ module.exports = {
); );
}); });
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'PROJECT_DELETE', event: 'projectDelete',
data: project, data: {
projectId: project.id, item: project,
user: inputs.request.currentUser, },
user: inputs.actorUser,
}); });
} }

View file

@ -28,6 +28,10 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -109,11 +113,12 @@ module.exports = {
); );
}); });
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'PROJECT_UPDATE', event: 'projectUpdate',
data: project, data: {
projectId: project.id, item: project,
user: inputs.request.currentUser, },
user: inputs.actorUser,
}); });
} }

View file

@ -21,10 +21,22 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -54,6 +66,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
const task = await Task.create({ const task = await Task.create({
@ -71,13 +85,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'TASK_CREATE', event: 'taskCreate',
data: task, data: {
projectId: inputs.board.projectId, item: task,
user: inputs.request.currentUser, included: {
card: values.card, projects: [inputs.project],
board: inputs.board, boards: [inputs.board],
lists: [inputs.list],
cards: [values.card],
},
},
user: inputs.actorUser,
}); });
return task; return task;

View file

@ -4,10 +4,26 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -26,12 +42,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'TASK_DELETE', event: 'taskDelete',
data: task, data: {
projectId: inputs.board.projectId, item: task,
user: inputs.request.currentUser, included: {
board: inputs.board, projects: [inputs.project],
boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -21,10 +21,26 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
project: {
type: 'ref',
required: true,
},
board: { board: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
list: {
type: 'ref',
required: true,
},
card: {
type: 'ref',
required: true,
},
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -57,6 +73,8 @@ module.exports = {
position: nextPosition, position: nextPosition,
}, },
}); });
// TODO: send webhooks
}); });
} }
@ -72,13 +90,18 @@ module.exports = {
inputs.request, inputs.request,
); );
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'TASK_UPDATE', event: 'taskUpdate',
data: task, data: {
projectId: inputs.board.projectId, item: task,
user: inputs.request.currentUser, included: {
card: values.card, projects: [inputs.project],
board: inputs.board, boards: [inputs.board],
lists: [inputs.list],
cards: [inputs.card],
},
},
user: inputs.actorUser,
}); });
} }

View file

@ -27,6 +27,10 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -84,21 +88,12 @@ module.exports = {
); );
}); });
/* The user could be created manually by an user or via OIDC. We hijack the id field, so one can differentiate between the two on the webhook side. */ sails.helpers.utils.sendWebhooks.with({
let initiator; event: 'userCreate',
if (inputs.request && inputs.request.currentUser) { data: {
initiator = inputs.request.currentUser; item: user,
} else { },
initiator = { user: inputs.actorUser,
id: 'oidc',
};
}
await sails.helpers.utils.sendWebhook.with({
event: 'USER_CREATE',
data: { ...user, password: undefined },
projectId: '',
user: initiator,
}); });
return user; return user;

View file

@ -4,6 +4,10 @@ module.exports = {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
actorUser: {
type: 'ref',
required: true,
},
request: { request: {
type: 'ref', type: 'ref',
}, },
@ -60,11 +64,12 @@ module.exports = {
); );
}); });
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'USER_DELETE', event: 'userDelete',
data: { ...user, password: undefined }, data: {
projectId: '', item: user,
user: inputs.request.currentUser, },
user: inputs.actorUser,
}); });
} }

View file

@ -88,8 +88,11 @@ module.exports = {
// Otherwise, create a new user. // Otherwise, create a new user.
if (!user) { if (!user) {
user = await sails.helpers.users user = await sails.helpers.users.createOne
.createOne(values) .with({
values,
actorUser: User.OIDC,
})
.intercept('usernameAlreadyInUse', 'usernameAlreadyInUse'); .intercept('usernameAlreadyInUse', 'usernameAlreadyInUse');
} }
@ -115,8 +118,12 @@ module.exports = {
} }
if (Object.keys(updateValues).length > 0) { if (Object.keys(updateValues).length > 0) {
user = await sails.helpers.users user = await sails.helpers.users.updateOne
.updateOne(user, updateValues, {}) // FIXME: hack for last parameter .with({
record: user,
values: updateValues,
actorUser: User.OIDC,
})
.intercept('emailAlreadyInUse', 'emailAlreadyInUse') .intercept('emailAlreadyInUse', 'emailAlreadyInUse')
.intercept('usernameAlreadyInUse', 'usernameAlreadyInUse'); .intercept('usernameAlreadyInUse', 'usernameAlreadyInUse');
} }

View file

@ -38,7 +38,7 @@ module.exports = {
custom: valuesValidator, custom: valuesValidator,
required: true, required: true,
}, },
user: { actorUser: {
type: 'ref', type: 'ref',
required: true, required: true,
}, },
@ -62,14 +62,14 @@ module.exports = {
let isOnlyPasswordChange = false; let isOnlyPasswordChange = false;
if (!_.isUndefined(values.password)) { if (!_.isUndefined(values.password)) {
if (Object.keys(values).length === 1) {
isOnlyPasswordChange = true;
}
Object.assign(values, { Object.assign(values, {
password: bcrypt.hashSync(values.password, 10), password: bcrypt.hashSync(values.password, 10),
passwordChangedAt: new Date().toISOString(), passwordChangedAt: new Date().toISOString(),
}); });
if (Object.keys(values).length === 1) {
isOnlyPasswordChange = true;
}
} }
if (values.username) { if (values.username) {
@ -118,7 +118,7 @@ module.exports = {
inputs.request, inputs.request,
); );
if (user.id === inputs.user.id && inputs.request && inputs.request.isSocket) { if (user.id === inputs.actorUser.id && inputs.request && inputs.request.isSocket) {
const tempRoom = uuid(); const tempRoom = uuid();
sails.sockets.addRoomMembersToRooms(`@user:${user.id}`, tempRoom, () => { sails.sockets.addRoomMembersToRooms(`@user:${user.id}`, tempRoom, () => {
@ -153,14 +153,15 @@ module.exports = {
inputs.request, inputs.request,
); );
}); });
}
await sails.helpers.utils.sendWebhook.with({ sails.helpers.utils.sendWebhooks.with({
event: 'USER_UPDATE', event: 'userUpdate',
data: { ...user, password: undefined }, data: {
projectId: '', item: user,
user: inputs.request.currentUser, },
}); user: inputs.actorUser,
});
}
} }
return user; return user;

View file

@ -0,0 +1,14 @@
module.exports = {
sync: true,
inputs: {
record: {
type: 'ref',
required: true,
},
},
fn(inputs) {
return inputs.record.toJSON ? inputs.record.toJSON() : inputs.record;
},
};

View file

@ -1,4 +1,6 @@
module.exports = { module.exports = {
// TODO: make sync?
inputs: { inputs: {
to: { to: {
type: 'string', type: 'string',

View file

@ -1,6 +1,8 @@
const POST_MESSAGE_API_URL = 'https://slack.com/api/chat.postMessage'; const POST_MESSAGE_API_URL = 'https://slack.com/api/chat.postMessage';
module.exports = { module.exports = {
// TODO: make sync?
inputs: { inputs: {
markdown: { markdown: {
type: 'string', type: 'string',

View file

@ -1,115 +0,0 @@
const EVENT_TYPES = {
ACTION_CREATE: 'action_create',
ACTION_UPDATE: 'action_update',
ACTION_DELETE: 'action_delete',
CARD_CREATE: 'card_create',
CARD_UPDATE: 'card_update',
CARD_DELETE: 'card_delete',
CARD_MEMBERSHIP_CREATE: 'card_membership_create',
CARD_MEMBERSHIP_DELETE: 'card_membership_delete',
LIST_CREATE: 'list_create',
LIST_UPDATE: 'list_update',
LIST_DELETE: 'list_delete',
BOARD_CREATE: 'board_create',
BOARD_UPDATE: 'board_update',
BOARD_DELETE: 'board_delete',
ATTACHMENT_CREATE: 'attachment_create',
ATTACHMENT_UPDATE: 'attachment_update',
ATTACHMENT_DELETE: 'attachment_delete',
PROJECT_CREATE: 'project_create',
PROJECT_UPDATE: 'project_update',
PROJECT_DELETE: 'project_delete',
TASK_CREATE: 'task_create',
TASK_UPDATE: 'task_update',
TASK_DELETE: 'task_delete',
USER_CREATE: 'user_create',
USER_UPDATE: 'user_update',
USER_DELETE: 'user_delete',
};
/**
* Sends a webhook notification to a configured URL.
*
* @param {Object} inputs - Data to include in the webhook payload.
* @param {string} inputs.event - The event type (see {@link EVENT_TYPES}).
* @param {*} inputs.data - The actual data related to the event.
* @param {string} inputs.projectId - The project ID associated with the event.
* @param {ref} [inputs.user] - Optional user object associated with the event.
* @param {ref} [inputs.card] - Optional card object associated with the event.
* @param {ref} [inputs.board] - Optional board object associated with the event.
* @param {ref} [inputs.list] - Optional list object associated with the event.
* @returns {Promise<void>}
*/
async function sendWebhook(inputs) {
const url = sails.config.custom.webhookUrl;
const headers = {
'Content-Type': 'application/json',
};
if (sails.config.custom.webhookBearer) {
headers.Authorization = `Bearer ${sails.config.custom.webhookBearer}`;
}
const body = JSON.stringify({
...inputs,
user: {
...inputs.user,
password: undefined,
},
});
const req = await fetch(url, {
method: 'POST',
headers,
body,
});
if (req.status !== 200) {
sails.log.error(`Webhook failed with status ${req.status} and message: ${await req.text()}`);
}
}
module.exports = {
eventTypes: EVENT_TYPES,
inputs: {
event: {
type: 'string',
isIn: Object.keys(EVENT_TYPES),
required: true,
},
data: {
type: 'ref',
required: true,
},
projectId: {
type: 'string',
default: '',
},
user: {
type: 'ref',
},
card: {
type: 'ref',
},
board: {
type: 'ref',
},
list: {
type: 'ref',
},
},
async fn(inputs) {
if (!sails.config.custom.webhookUrl) return;
try {
await sendWebhook(inputs);
} catch (err) {
sails.log.error(err);
}
},
};

View file

@ -0,0 +1,103 @@
const jsonifyData = (data) => {
const nextData = {};
if (data.item) {
nextData.item = sails.helpers.utils.jsonifyRecord(data.item);
}
if (data.items) {
nextData.items = data.items.map((item) => sails.helpers.utils.jsonifyRecord(item));
}
if (data.included) {
nextData.included = Object.entries(data.included).reduce(
(result, [key, items]) => ({
...result,
[key]: items.map((item) => sails.helpers.utils.jsonifyRecord(item)),
}),
{},
);
}
return nextData;
};
/**
* Sends a webhook notification to a configured URL.
*
* @param {*} webhook - Webhook configuration.
* @param {string} event - The event (see {@link Events}).
* @param {*} data - The actual data related to the event.
* @param {ref} user - User object associated with the event.
* @returns {Promise<void>}
*/
async function sendWebhook(webhook, event, data, user) {
const headers = {
'Content-Type': 'application/json',
};
if (webhook.accessToken) {
headers.Authorization = `Bearer ${webhook.accessToken}`;
}
const body = JSON.stringify({
event,
data: jsonifyData(data),
user: sails.helpers.utils.jsonifyRecord(user),
});
const response = await fetch(webhook.url, {
headers,
body,
method: 'POST',
});
if (!response.ok) {
const message = await response.text();
sails.log.error(
`Webhook ${webhook.url} failed with status ${response.status} and message: ${message}`,
);
}
}
module.exports = {
sync: true,
inputs: {
event: {
type: 'string',
required: true,
},
data: {
type: 'ref',
required: true,
},
user: {
type: 'ref',
required: true,
},
},
fn(inputs) {
if (!sails.config.custom.webhooks) {
return;
}
sails.config.custom.webhooks.forEach((webhook) => {
if (!webhook.url) {
return;
}
if (webhook.excludedEvents && webhook.excludedEvents.includes(inputs.event)) {
return;
}
if (webhook.events && !webhook.events.includes(inputs.event)) {
return;
}
sendWebhook(webhook, inputs.event, inputs.data, inputs.user);
});
},
};

View file

@ -5,7 +5,13 @@
* @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models
*/ */
const OIDC = {
id: '_oidc',
};
module.exports = { module.exports = {
OIDC,
attributes: { attributes: {
// ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗
// ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗ // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗

View file

@ -60,9 +60,8 @@ module.exports.custom = {
smtpPassword: process.env.SMTP_PASSWORD, smtpPassword: process.env.SMTP_PASSWORD,
smtpFrom: process.env.SMTP_FROM, smtpFrom: process.env.SMTP_FROM,
webhooks: JSON.parse(process.env.WEBHOOKS), // TODO: validate structure
slackBotToken: process.env.SLACK_BOT_TOKEN, slackBotToken: process.env.SLACK_BOT_TOKEN,
slackChannelId: process.env.SLACK_CHANNEL_ID, slackChannelId: process.env.SLACK_CHANNEL_ID,
webhookUrl: process.env.WEBHOOK_URL,
webhookBearer: process.env.WEBHOOK_BEARER,
}; };