1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-19 13:19:44 +02:00

feat: Version 2

Closes #627, closes #1047
This commit is contained in:
Maksim Eltyshev 2025-05-10 02:09:06 +02:00
parent ad7fb51cfa
commit 2ee1166747
1557 changed files with 76832 additions and 47042 deletions

View file

@ -0,0 +1,55 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
/**
* query-methods hook
*
* @description :: A hook definition. Extends Sails by adding shadow routes, implicit actions,
* and/or initialization logic.
* @docs :: https://sailsjs.com/docs/concepts/extending-sails/hooks
*/
const fs = require('fs');
const path = require('path');
module.exports = function defineQueryMethodsHook(sails) {
const addQueryMethods = () => {
const queryMethodsByModelName = fs.readdirSync(path.join(__dirname, 'models')).reduce(
(result, filename) => ({
...result,
// eslint-disable-next-line global-require, import/no-dynamic-require
[path.parse(filename).name]: require(path.join(__dirname, 'models', filename)),
}),
{},
);
_(sails.models).forEach((Model) => {
const queryMethods = queryMethodsByModelName[Model.globalId];
if (queryMethods) {
Object.assign(Model, {
qm: queryMethods,
});
}
});
};
return {
/**
* Runs when this Sails app loads/lifts.
*/
async initialize() {
sails.log.info('Initializing custom hook (`query-methods`)');
return new Promise((resolve) => {
sails.after('hook:orm:loaded', () => {
addQueryMethods();
resolve();
});
});
},
};
};

View file

@ -0,0 +1,39 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const LIMIT = 50;
/* Query methods */
const create = (arrayOfValues) => Action.createEach(arrayOfValues).fetch();
const createOne = (values) => Action.create({ ...values }).fetch();
const getByCardId = (cardId, { beforeId } = {}) => {
const criteria = {
cardId,
};
if (beforeId) {
criteria.id = {
'<': beforeId,
};
}
return Action.find(criteria).sort('id DESC').limit(LIMIT);
};
const update = (criteria, values) => Action.update(criteria).set(values).fetch();
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Action.destroy(criteria).fetch();
module.exports = {
create,
createOne,
getByCardId,
update,
delete: delete_,
};

View file

@ -0,0 +1,231 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
// TODO: refactor?
const defaultFind = (criteria) => Attachment.find(criteria).sort('id');
/* Query methods */
const create = (arrayOfValues) => {
const arrayOfFileValues = arrayOfValues.filter(({ type }) => type === Attachment.Types.FILE);
if (arrayOfFileValues.length > 0) {
const arrayOfValuesByFileReferenceId = _.groupBy(arrayOfFileValues, 'data.fileReferenceId');
const fileReferenceIds = Object.keys(arrayOfValuesByFileReferenceId);
const fileReferenceIdsByTotal = Object.entries(arrayOfValuesByFileReferenceId).reduce(
(result, [fileReferenceId, arrayOfValuesItem]) => ({
...result,
[arrayOfValuesItem.length]: [...(result[arrayOfValuesItem.length] || []), fileReferenceId],
}),
{},
);
return sails.getDatastore().transaction(async (db) => {
const queryValues = [];
let query = `UPDATE file_reference SET total = total + CASE `;
Object.entries(fileReferenceIdsByTotal).forEach(([total, fileReferenceIdsItem]) => {
const inValues = fileReferenceIdsItem.map((fileReferenceId) => {
queryValues.push(fileReferenceId);
return `$${queryValues.length}`;
});
queryValues.push(total);
query += `WHEN id IN (${inValues.join(', ')}) THEN $${queryValues.length}::int `;
});
const inValues = fileReferenceIds.map((fileReferenceId) => {
queryValues.push(fileReferenceId);
return `$${queryValues.length}`;
});
queryValues.push(new Date().toISOString());
query += `END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND total IS NOT NULL RETURNING id`;
const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db);
const nextFileReferenceIds = sails.helpers.utils.mapRecords(queryResult.rows);
if (nextFileReferenceIds.length < fileReferenceIds.length) {
const nextFileReferenceIdsSet = new Set(nextFileReferenceIds);
// eslint-disable-next-line no-param-reassign
arrayOfValues = arrayOfValues.filter(
(values) =>
values.type !== Attachment.Types.FILE ||
nextFileReferenceIdsSet.has(values.data.fileReferenceId),
);
}
return Attachment.createEach(arrayOfValues).fetch().usingConnection(db);
});
}
return Attachment.createEach(arrayOfValues).fetch();
};
const createOne = (values) => {
if (values.type === Attachment.Types.FILE) {
const { fileReferenceId } = values.data;
return sails.getDatastore().transaction(async (db) => {
const attachment = await Attachment.create({ ...values })
.fetch()
.usingConnection(db);
const queryResult = await sails
.sendNativeQuery(
'UPDATE file_reference SET total = total + 1, updated_at = $1 WHERE id = $2 AND total IS NOT NULL',
[new Date().toISOString(), fileReferenceId],
)
.usingConnection(db);
if (queryResult.rowCount === 0) {
throw 'fileReferenceNotFound';
}
return attachment;
});
}
return Attachment.create({ ...values }).fetch();
};
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId) =>
defaultFind({
cardId,
});
const getByCardIds = (cardIds) =>
defaultFind({
cardId: cardIds,
});
const getOneById = (id, { cardId } = {}) => {
const criteria = {
id,
};
if (cardId) {
criteria.cardId = cardId;
}
return Attachment.findOne(criteria);
};
const update = (criteria, values) => Attachment.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => Attachment.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) =>
sails.getDatastore().transaction(async (db) => {
const attachments = await Attachment.destroy(criteria).fetch().usingConnection(db);
const fileAttachments = attachments.filter(({ type }) => type === Attachment.Types.FILE);
let fileReferences = [];
if (fileAttachments.length > 0) {
const attachmentsByFileReferenceId = _.groupBy(fileAttachments, 'data.fileReferenceId');
const fileReferenceIdsByTotal = Object.entries(attachmentsByFileReferenceId).reduce(
(result, [fileReferenceId, attachmentsItem]) => ({
...result,
[attachmentsItem.length]: [...(result[attachmentsItem.length] || []), fileReferenceId],
}),
{},
);
const queryValues = [];
let query = 'UPDATE file_reference SET total = CASE WHEN total = CASE ';
Object.entries(fileReferenceIdsByTotal).forEach(([total, fileReferenceIds]) => {
const inValues = fileReferenceIds.map((fileReferenceId) => {
queryValues.push(fileReferenceId);
return `$${queryValues.length}`;
});
queryValues.push(total);
query += `WHEN id IN (${inValues.join(', ')}) THEN $${queryValues.length}::int `;
});
query += 'END THEN NULL ELSE total - CASE ';
Object.entries(fileReferenceIdsByTotal).forEach(([total, fileReferenceIds]) => {
const inValues = fileReferenceIds.map((fileReferenceId) => {
queryValues.push(fileReferenceId);
return `$${queryValues.length}`;
});
queryValues.push(total);
query += `WHEN id IN (${inValues.join(', ')}) THEN $${queryValues.length}::int `;
});
const inValues = Object.keys(attachmentsByFileReferenceId).map((fileReferenceId) => {
queryValues.push(fileReferenceId);
return `$${queryValues.length}`;
});
queryValues.push(new Date().toISOString());
query += `END END, updated_at = $${queryValues.length} WHERE id IN (${inValues.join(', ')}) AND total IS NOT NULL RETURNING id, total`;
const queryResult = await sails.sendNativeQuery(query, queryValues).usingConnection(db);
fileReferences = queryResult.rows;
}
return {
attachments,
fileReferences,
};
});
const deleteOne = async (criteria, { isFile } = {}) => {
let fileReference = null;
if (isFile) {
return sails.getDatastore().transaction(async (db) => {
const attachment = await Attachment.destroyOne(criteria).usingConnection(db);
if (attachment.type === Attachment.Types.FILE) {
const queryResult = await sails
.sendNativeQuery(
'UPDATE file_reference SET total = CASE WHEN total > 1 THEN total - 1 END, updated_at = $1 WHERE id = $2 RETURNING id, total',
[new Date().toISOString(), attachment.data.fileReferenceId],
)
.usingConnection(db);
[fileReference] = queryResult.rows;
}
return {
attachment,
fileReference,
};
});
}
const attachment = await Attachment.destroyOne(criteria);
return {
attachment,
fileReference,
};
};
module.exports = {
create,
createOne,
getByIds,
getByCardId,
getByCardIds,
getOneById,
update,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,49 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => BackgroundImage.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => BackgroundImage.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByProjectId = (projectId) =>
defaultFind({
projectId,
});
const getByProjectIds = (projectIds) =>
defaultFind({
projectId: projectIds,
});
const getOneById = (id, { projectId } = {}) => {
const criteria = {
id,
};
if (projectId) {
criteria.projectId = projectId;
}
return BackgroundImage.findOne(criteria);
};
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => BackgroundImage.destroy(criteria).fetch();
const deleteOne = (criteria) => BackgroundImage.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByProjectId,
getByProjectIds,
getOneById,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,52 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => BaseCustomFieldGroup.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => BaseCustomFieldGroup.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByProjectId = (projectId) =>
defaultFind({
projectId,
});
const getByProjectIds = (projectIds) =>
defaultFind({
projectId: projectIds,
});
const getOneById = (id, { projectId } = {}) => {
const criteria = {
id,
};
if (projectId) {
criteria.projectId = projectId;
}
return BaseCustomFieldGroup.findOne(criteria);
};
const updateOne = (criteria, values) => BaseCustomFieldGroup.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => BaseCustomFieldGroup.destroy(criteria).fetch();
const deleteOne = (criteria) => BaseCustomFieldGroup.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByProjectId,
getByProjectIds,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,91 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { sort = 'id' } = {}) => Board.find(criteria).sort(sort);
/* Query methods */
const createOne = (values, { user } = {}) =>
sails.getDatastore().transaction(async (db) => {
const board = await Board.create({ ...values })
.fetch()
.usingConnection(db);
const boardMembership = await BoardMembership.create({
projectId: board.projectId,
boardId: board.id,
userId: user.id,
role: BoardMembership.Roles.EDITOR,
})
.fetch()
.usingConnection(db);
const lists = await List.createEach(
[List.Types.ARCHIVE, List.Types.TRASH].map((type) => ({
type,
boardId: board.id,
})),
)
.fetch()
.usingConnection(db);
return { board, boardMembership, lists };
});
const getByIds = (ids, { exceptProjectIdOrIds } = {}) => {
const criteria = {
id: ids,
};
if (exceptProjectIdOrIds) {
criteria.projectId = {
'!=': exceptProjectIdOrIds,
};
}
return defaultFind(criteria);
};
const getByProjectId = (projectId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
projectId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getByProjectIds = (projectIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
projectId: projectIds,
},
{ sort },
);
const getOneById = (id) => Board.findOne(id);
const updateOne = (criteria, values) => Board.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Board.destroy(criteria).fetch();
const deleteOne = (criteria) => Board.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByProjectId,
getByProjectIds,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,100 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => BoardMembership.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => BoardMembership.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByProjectId = (projectId) =>
defaultFind({
projectId,
});
const getByProjectIdAndUserId = (projectId, userId) =>
defaultFind({
projectId,
userId,
});
const getByProjectIds = (projectIds) =>
defaultFind({
projectId: projectIds,
});
const getByBoardId = (boardId) =>
defaultFind({
boardId,
});
const getByBoardIds = (boardIds, { exceptUserIdOrIds } = {}) => {
const criteria = {
boardId: boardIds,
};
if (exceptUserIdOrIds) {
criteria.userId = {
'!=': exceptUserIdOrIds,
};
}
return defaultFind(criteria);
};
const getByBoardIdsAndUserId = (boardIds, userId) =>
defaultFind({
userId,
boardId: boardIds,
});
const getByUserId = (userId, { exceptProjectIdOrIds } = {}) => {
const criteria = {
userId,
};
if (exceptProjectIdOrIds) {
criteria.projectId = {
'!=': exceptProjectIdOrIds,
};
}
return defaultFind(criteria);
};
const getOneById = (id) => BoardMembership.findOne(id);
const getOneByBoardIdAndUserId = (boardId, userId) =>
BoardMembership.findOne({
boardId,
userId,
});
const updateOne = async (criteria, values) =>
BoardMembership.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => BoardMembership.destroy(criteria).fetch();
const deleteOne = (criteria) => BoardMembership.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByProjectId,
getByProjectIdAndUserId,
getByProjectIds,
getByBoardId,
getByBoardIds,
getByBoardIdsAndUserId,
getByUserId,
getOneById,
getOneByBoardIdAndUserId,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,46 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => BoardSubscription.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => BoardSubscription.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId, { exceptUserIdOrIds } = {}) => {
const criteria = {
boardId,
};
if (exceptUserIdOrIds) {
criteria.userId = {
'!=': exceptUserIdOrIds,
};
}
return defaultFind(criteria);
};
const getOneByBoardIdAndUserId = (boardId, userId) =>
BoardSubscription.findOne({
boardId,
userId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => BoardSubscription.destroy(criteria).fetch();
const deleteOne = (criteria) => BoardSubscription.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByBoardId,
getOneByBoardIdAndUserId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,224 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const LIMIT = 50;
const SEARCH_PARTS_REGEX = /[ ,;]+/;
const defaultFind = (criteria, { sort = 'id', limit } = {}) =>
Card.find(criteria).sort(sort).limit(limit);
/* Query methods */
const getIdsByEndlessListId = async (
listId,
{ before, search, filterUserIds, filterLabelIds } = {},
) => {
if (filterUserIds && filterUserIds.length === 0) {
return [];
}
if (filterLabelIds && filterLabelIds.length === 0) {
return [];
}
const queryValues = [];
let query = 'SELECT DISTINCT card.id FROM card';
if (filterUserIds) {
query += ' JOIN card_membership ON card.id = card_membership.card_id';
}
if (filterLabelIds) {
query += ' JOIN card_label ON card.id = card_label.card_id';
}
queryValues.push(listId);
query += ` WHERE card.list_id = $${queryValues.length}`;
if (before) {
queryValues.push(before.listChangedAt);
query += ` AND (card.list_changed_at < $${queryValues.length} OR (card.list_changed_at = $${queryValues.length}`;
queryValues.push(before.id);
query += ` AND card.id < $${queryValues.length}))`;
}
if (search) {
if (search.startsWith('/')) {
queryValues.push(search.substring(1));
query += ` AND (card.name ~* $${queryValues.length} OR card.description ~* $${queryValues.length})`;
} else {
const searchParts = search.split(SEARCH_PARTS_REGEX).flatMap((searchPart) => {
if (!searchPart) {
return [];
}
return searchPart.toLowerCase();
});
if (searchParts.length > 0) {
let ilikeValues = searchParts.map((searchPart) => {
queryValues.push(searchPart);
return `'%' || $${queryValues.length} || '%'`;
});
query += ` AND ((card.name ILIKE ALL(ARRAY[${ilikeValues.join(', ')}]))`;
ilikeValues = searchParts.map((searchPart) => {
queryValues.push(searchPart);
return `'%' || $${queryValues.length} || '%'`;
});
query += ` OR (card.description ILIKE ALL(ARRAY[${ilikeValues.join(', ')}])))`;
}
}
}
if (filterUserIds) {
const inValues = filterUserIds.map((filterUserId) => {
queryValues.push(filterUserId);
return `$${queryValues.length}`;
});
query += ` AND card_membership.user_id IN (${inValues.join(', ')})`;
}
if (filterLabelIds) {
const inValues = filterLabelIds.map((filterLabelId) => {
queryValues.push(filterLabelId);
return `$${queryValues.length}`;
});
query += ` AND card_label.label_id IN (${inValues.join(', ')})`;
}
query += ` LIMIT ${LIMIT}`;
let queryResult;
try {
queryResult = await sails.sendNativeQuery(query, queryValues);
} catch (error) {
if (
error.code === 'E_QUERY_FAILED' &&
error.message.includes('Query failed: invalid regular expression')
) {
return [];
}
throw error;
}
return sails.helpers.utils.mapRecords(queryResult.rows);
};
const createOne = (values) => Card.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId) =>
defaultFind({
boardId,
});
const getByListId = async (listId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
listId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getByEndlessListId = async (listId, { before, search, filterUserIds, filterLabelIds }) => {
const criteria = {};
const options = {
sort: ['listChangedAt DESC', 'id DESC'],
};
if (search || filterUserIds || filterLabelIds) {
criteria.id = await getIdsByEndlessListId(listId, {
before,
search,
filterUserIds,
filterLabelIds,
});
} else {
criteria.and = [{ listId }];
if (before) {
criteria.and.push({
or: [
{
listChangedAt: {
'<': before.listChangedAt,
},
},
{
listChangedAt: before.listChangedAt,
id: {
'<': before.id,
},
},
],
});
}
options.limit = LIMIT;
}
return defaultFind(criteria, options);
};
const getByListIds = async (listIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
listId: listIds,
},
{ sort },
);
const getOneById = (id, { listId } = {}) => {
const criteria = {
id,
};
if (listId) {
criteria.listId = listId;
}
return Card.findOne(criteria);
};
const update = (criteria, values) => Card.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => Card.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Card.destroy(criteria).fetch();
const deleteOne = (criteria) => Card.destroyOne(criteria);
module.exports = {
getIdsByEndlessListId,
createOne,
getByIds,
getByBoardId,
getByListId,
getByEndlessListId,
getByListIds,
getOneById,
update,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,46 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => CardLabel.find(criteria).sort('id');
/* Query methods */
const create = (arrayOfValues) => CardLabel.createEach(arrayOfValues).fetch();
const createOne = (values) => CardLabel.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId) =>
defaultFind({
cardId,
});
const getByCardIds = (cardIds) =>
defaultFind({
cardId: cardIds,
});
const getOneByCardIdAndLabelId = (cardId, labelId) =>
CardLabel.findOne({
cardId,
labelId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CardLabel.destroy(criteria).fetch();
const deleteOne = (criteria) => CardLabel.destroyOne(criteria);
module.exports = {
create,
createOne,
getByIds,
getByCardId,
getByCardIds,
getOneByCardIdAndLabelId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,46 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => CardMembership.find(criteria).sort('id');
/* Query methods */
const create = (arrayOfValues) => CardMembership.createEach(arrayOfValues).fetch();
const createOne = (values) => CardMembership.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId) =>
defaultFind({
cardId,
});
const getByCardIds = (cardIds) =>
defaultFind({
cardId: cardIds,
});
const getOneByCardIdAndUserId = (cardId, userId) =>
CardMembership.findOne({
cardId,
userId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CardMembership.destroy(criteria).fetch();
const deleteOne = (criteria) => CardMembership.destroyOne(criteria);
module.exports = {
create,
createOne,
getByIds,
getByCardId,
getByCardIds,
getOneByCardIdAndUserId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,53 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => CardSubscription.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => CardSubscription.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId, { exceptUserIdOrIds } = {}) => {
const criteria = {
cardId,
};
if (exceptUserIdOrIds) {
criteria.userId = {
'!=': exceptUserIdOrIds,
};
}
return defaultFind(criteria);
};
const getByCardIdsAndUserId = (cardIds, userId) =>
defaultFind({
userId,
cardId: cardIds,
});
const getOneByCardIdAndUserId = (cardId, userId) =>
CardSubscription.findOne({
cardId,
userId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CardSubscription.destroy(criteria).fetch();
const deleteOne = (criteria) => CardSubscription.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByCardId,
getByCardIdsAndUserId,
getOneByCardIdAndUserId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,51 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const LIMIT = 50;
const defaultFind = (criteria, { limit } = {}) =>
Comment.find(criteria).sort('id DESC').limit(limit);
/* Query methods */
const createOne = (values) => Comment.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId, { beforeId } = {}) => {
const criteria = {
cardId,
};
if (beforeId) {
criteria.id = {
'<': beforeId,
};
}
return defaultFind(criteria, { limit: LIMIT });
};
const getOneById = (id) => Comment.findOne(id);
const update = (criteria, values) => Comment.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => Comment.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Comment.destroy(criteria).fetch();
const deleteOne = (criteria) => Comment.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByCardId,
getOneById,
update,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,87 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { exceptIdOrIds, sort = 'id' } = {}) => {
if (exceptIdOrIds) {
// eslint-disable-next-line no-param-reassign
criteria.id = {
'!=': exceptIdOrIds,
};
}
return CustomField.find(criteria).sort(sort);
};
/* Query methods */
const create = (arrayOfValues) => CustomField.createEach(arrayOfValues).fetch();
const createOne = (values) => CustomField.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBaseCustomFieldGroupId = (
baseCustomFieldGroupId,
{ exceptIdOrIds, sort = ['position', 'id'] } = {},
) =>
defaultFind(
{
baseCustomFieldGroupId,
},
{ exceptIdOrIds, sort },
);
const getByBaseCustomFieldGroupIds = (
baseCustomFieldGroupIds,
{ sort = ['position', 'id'] } = {},
) =>
defaultFind(
{
baseCustomFieldGroupId: baseCustomFieldGroupIds,
},
{ sort },
);
const getByCustomFieldGroupId = async (
customFieldGroupId,
{ exceptIdOrIds, sort = ['position', 'id'] } = {},
) =>
defaultFind(
{
customFieldGroupId,
},
{ exceptIdOrIds, sort },
);
const getByCustomFieldGroupIds = async (customFieldGroupIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
customFieldGroupId: customFieldGroupIds,
},
{ sort },
);
const getOneById = (id) => CustomField.findOne(id);
const updateOne = (criteria, values) => CustomField.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CustomField.destroy(criteria).fetch();
const deleteOne = (criteria) => CustomField.destroyOne(criteria);
module.exports = {
create,
createOne,
getByIds,
getByBaseCustomFieldGroupId,
getByBaseCustomFieldGroupIds,
getByCustomFieldGroupId,
getByCustomFieldGroupIds,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,72 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { exceptIdOrIds, sort = 'id' } = {}) => {
if (exceptIdOrIds) {
// eslint-disable-next-line no-param-reassign
criteria.id = {
'!=': exceptIdOrIds,
};
}
return CustomFieldGroup.find(criteria).sort(sort);
};
/* Query methods */
const create = (arrayOfValues) => CustomFieldGroup.createEach(arrayOfValues).fetch();
const createOne = (values) => CustomFieldGroup.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) =>
defaultFind(
{
boardId,
},
{ exceptIdOrIds, sort },
);
const getByCardId = (cardId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) =>
defaultFind(
{
cardId,
},
{ exceptIdOrIds, sort },
);
const getByCardIds = (cardIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
cardId: cardIds,
},
{ sort },
);
const getOneById = (id) => CustomFieldGroup.findOne(id);
const update = (criteria, values) => CustomFieldGroup.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => CustomFieldGroup.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CustomFieldGroup.destroy(criteria).fetch();
const deleteOne = (criteria) => CustomFieldGroup.destroyOne(criteria);
module.exports = {
create,
createOne,
getByBoardId,
getByIds,
getByCardId,
getByCardIds,
getOneById,
update,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,95 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => CustomFieldValue.find(criteria).sort('id');
/* Query methods */
const create = (arrayOfValues) => CustomFieldValue.createEach(arrayOfValues).fetch();
const createOrUpdateOne = async (values) => {
const query = `
INSERT INTO custom_field_value (card_id, custom_field_group_id, custom_field_id, content, created_at)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (card_id, custom_field_group_id, custom_field_id)
DO UPDATE SET content = EXCLUDED.content, updated_at = EXCLUDED.created_at
RETURNING *
`;
const queryResult = await sails.sendNativeQuery(query, [
values.cardId,
values.customFieldGroupId,
values.customFieldId,
values.content,
new Date().toISOString(),
]);
const [customFieldValue] = queryResult.rows;
return {
id: customFieldValue.id,
cardId: customFieldValue.card_id,
customFieldGroupId: customFieldValue.custom_field_group_id,
customFieldId: customFieldValue.custom_field_id,
content: customFieldValue.content,
createdAt: customFieldValue.created_at,
updatedAt: customFieldValue.updated_at,
};
};
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId, { customFieldGroupIdOrIds } = {}) => {
const criteria = {
cardId,
};
if (customFieldGroupIdOrIds) {
criteria.customFieldGroupId = customFieldGroupIdOrIds;
}
return defaultFind(criteria);
};
const getByCardIds = (cardIds) =>
defaultFind({
cardId: cardIds,
});
const getByCustomFieldGroupId = (customFieldGroupId) =>
defaultFind({
customFieldGroupId,
});
const getOneByCardIdAndCustomFieldGroupIdAndCustomFieldId = (
cardId,
customFieldGroupId,
customFieldId,
) =>
CustomFieldValue.findOne({
cardId,
customFieldGroupId,
customFieldId,
});
const updateOne = (criteria, values) => CustomFieldValue.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => CustomFieldValue.destroy(criteria).fetch();
const deleteOne = (criteria) => CustomFieldValue.destroyOne(criteria);
module.exports = {
create,
createOrUpdateOne,
getByIds,
getByCardId,
getByCardIds,
getByCustomFieldGroupId,
getOneByCardIdAndCustomFieldGroupIdAndCustomFieldId,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,21 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const createOne = (values) => IdentityProviderUser.create({ ...values }).fetch();
const getOneByIssuerAndSub = (issuer, sub) =>
IdentityProviderUser.findOne({
issuer,
sub,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => IdentityProviderUser.destroy(criteria).fetch();
module.exports = {
createOne,
getOneByIssuerAndSub,
delete: delete_,
};

View file

@ -0,0 +1,55 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { sort = 'id' } = {}) => Label.find(criteria).sort(sort);
/* Query methods */
const createOne = (values) => Label.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
boardId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getOneById = (id, { boardId } = {}) => {
const criteria = {
id,
};
if (boardId) {
criteria.boardId = boardId;
}
return Label.findOne(criteria);
};
const updateOne = (criteria, values) => Label.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Label.destroy(criteria).fetch();
const deleteOne = (criteria) => Label.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByBoardId,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,66 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { sort = 'id' } = {}) => List.find(criteria).sort(sort);
/* Query methods */
const createOne = (values) => List.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByBoardId = (boardId, { exceptIdOrIds, typeOrTypes, sort = ['position', 'id'] } = {}) => {
const criteria = {
boardId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
if (typeOrTypes) {
criteria.type = typeOrTypes;
}
return defaultFind(criteria, { sort });
};
const getOneById = (id, { boardId } = {}) => {
const criteria = {
id,
};
if (boardId) {
criteria.boardId = boardId;
}
return List.findOne(criteria);
};
const getOneTrashByBoardId = (boardId) =>
List.findOne({
boardId,
type: List.Types.TRASH,
});
const updateOne = (criteria, values) => List.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => List.destroy(criteria).fetch();
const deleteOne = (criteria) => List.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByBoardId,
getOneById,
getOneTrashByBoardId,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,76 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const LIMIT = 100;
const defaultFind = (criteria) => Notification.find(criteria).sort('id DESC');
/* Query methods */
const createOne = (values) => {
if (values.userId) {
return sails.getDatastore().transaction(async (db) => {
const notification = await Notification.create({ ...values })
.fetch()
.usingConnection(db);
const query = `
WITH exceeded_notification AS (
SELECT id
FROM notification
WHERE user_id = $1 AND is_read = FALSE
ORDER BY id DESC
OFFSET $2
)
UPDATE notification
SET is_read = TRUE
WHERE id in (SELECT id FROM exceeded_notification)
`;
await sails.sendNativeQuery(query, [values.userId, LIMIT]).usingConnection(db);
return notification;
});
}
return Notification.create({ ...values }).fetch();
};
const getByIds = (ids) => defaultFind(ids);
const getUnreadByUserId = (userId) =>
defaultFind({
userId,
isRead: false,
});
const getOneById = (id, { userId } = {}) => {
const criteria = {
id,
};
if (userId) {
criteria.userId = userId;
}
return Notification.findOne(criteria);
};
const update = (criteria, values) => Notification.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => Notification.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Notification.destroy(criteria).fetch();
module.exports = {
createOne,
getByIds,
getUnreadByUserId,
getOneById,
update,
updateOne,
delete: delete_,
};

View file

@ -0,0 +1,45 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => NotificationService.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => NotificationService.create({ ...values }).fetch();
const getByUserId = (userId) =>
defaultFind({
userId,
});
const getByBoardId = (boardId) =>
defaultFind({
boardId,
});
const getByBoardIds = (boardIds) =>
defaultFind({
boardId: boardIds,
});
const getOneById = (id) => NotificationService.findOne(id);
const updateOne = (criteria, values) => NotificationService.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => NotificationService.destroy(criteria).fetch();
const deleteOne = (criteria) => NotificationService.destroyOne(criteria);
module.exports = {
createOne,
getByUserId,
getByBoardId,
getByBoardIds,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,67 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => Project.find(criteria).sort('id');
/* Query methods */
const createOne = (values, { user } = {}) =>
sails.getDatastore().transaction(async (db) => {
let project = await Project.create({ ...values })
.fetch()
.usingConnection(db);
const projectManager = await ProjectManager.create({
projectId: project.id,
userId: user.id,
})
.fetch()
.usingConnection(db);
if (values.type === Project.Types.PRIVATE) {
project = await Project.updateOne(project.id)
.set({
ownerProjectManagerId: projectManager.id,
})
.usingConnection(db);
}
return { project, projectManager };
});
const getByIds = (ids) => defaultFind(ids);
const getShared = ({ exceptIdOrIds } = {}) => {
const criteria = {
ownerProjectManagerId: null,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria);
};
const getOneById = (id) => Project.findOne(id);
const updateOne = (criteria, values) => Project.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Project.destroy(criteria).fetch();
const deleteOne = (criteria) => Project.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getShared,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,35 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => ProjectFavorite.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => ProjectFavorite.create({ ...values }).fetch();
const getByProjectIdsAndUserId = (projectIds, userId) =>
defaultFind({
userId,
projectId: projectIds,
});
const getOneByProjectIdAndUserId = (projectId, userId) =>
ProjectFavorite.findOne({
projectId,
userId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => ProjectFavorite.destroy(criteria).fetch();
const deleteOne = (criteria) => ProjectFavorite.destroyOne(criteria);
module.exports = {
createOne,
getByProjectIdsAndUserId,
getOneByProjectIdAndUserId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,80 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => ProjectManager.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => ProjectManager.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByProjectId = (projectId, { exceptIdOrIds } = {}) => {
const criteria = {
projectId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria);
};
const getByProjectIds = (projectIds, { exceptUserIdOrIds } = {}) => {
const criteria = {
projectId: projectIds,
};
if (exceptUserIdOrIds) {
criteria.userId = {
'!=': exceptUserIdOrIds,
};
}
return defaultFind(criteria);
};
const getByUserId = (userId) =>
defaultFind({
userId,
});
const getOneById = (id, { projectId } = {}) => {
const criteria = {
id,
};
if (projectId) {
criteria.projectId = projectId;
}
return ProjectManager.findOne(criteria);
};
const getOneByProjectIdAndUserId = (projectId, userId) =>
ProjectManager.findOne({
projectId,
userId,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => ProjectManager.destroy(criteria).fetch();
const deleteOne = (criteria) => ProjectManager.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getByProjectId,
getByProjectIds,
getByUserId,
getOneById,
getOneByProjectIdAndUserId,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,30 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const createOne = (values) => Session.create({ ...values }).fetch();
const getOneUndeletedByAccessToken = (accessToken) =>
Session.findOne({
accessToken,
deletedAt: null,
});
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Session.destroy(criteria).fetch();
const deleteOneById = (id) =>
Session.updateOne({
id,
deletedAt: null,
}).set({
deletedAt: new Date().toISOString(),
});
module.exports = {
createOne,
getOneUndeletedByAccessToken,
deleteOneById,
delete: delete_,
};

View file

@ -0,0 +1,71 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { sort = 'id', limit } = {}) =>
Task.find(criteria).sort(sort).limit(limit);
/* Query methods */
const create = (arrayOfValues) => Task.createEach(arrayOfValues).fetch();
const createOne = (values) => Task.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByTaskListId = async (taskListId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
taskListId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getByTaskListIds = async (taskListIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
taskListId: taskListIds,
},
{ sort },
);
const getOneById = (id, { taskListId } = {}) => {
const criteria = {
id,
};
if (taskListId) {
criteria.taskListId = taskListId;
}
return Task.findOne(criteria);
};
const update = (criteria, values) => Task.update(criteria).set(values).fetch();
const updateOne = (criteria, values) => Task.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => Task.destroy(criteria).fetch();
const deleteOne = (criteria) => Task.destroyOne(criteria);
module.exports = {
create,
createOne,
getByIds,
getByTaskListId,
getByTaskListIds,
getOneById,
update,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,67 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria, { sort = 'id' } = {}) => TaskList.find(criteria).sort(sort);
/* Query methods */
const create = (arrayOfValues) => TaskList.createEach(arrayOfValues).fetch();
const createOne = (values) => TaskList.create({ ...values }).fetch();
const getByIds = (ids) => defaultFind(ids);
const getByCardId = (cardId, { exceptIdOrIds, sort = ['position', 'id'] } = {}) => {
const criteria = {
cardId,
};
if (exceptIdOrIds) {
criteria.id = {
'!=': exceptIdOrIds,
};
}
return defaultFind(criteria, { sort });
};
const getByCardIds = (cardIds, { sort = ['position', 'id'] } = {}) =>
defaultFind(
{
cardId: cardIds,
},
{ sort },
);
const getOneById = (id, { cardId } = {}) => {
const criteria = {
id,
};
if (cardId) {
criteria.cardId = cardId;
}
return TaskList.findOne(criteria);
};
const updateOne = (criteria, values) => TaskList.updateOne(criteria).set({ ...values });
// eslint-disable-next-line no-underscore-dangle
const delete_ = (criteria) => TaskList.destroy(criteria).fetch();
const deleteOne = (criteria) => TaskList.destroyOne(criteria);
module.exports = {
create,
createOne,
getByIds,
getByCardId,
getByCardIds,
getOneById,
updateOne,
deleteOne,
delete: delete_,
};

View file

@ -0,0 +1,98 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const defaultFind = (criteria) => User.find(criteria).sort('id');
/* Query methods */
const createOne = (values) => {
if (sails.config.custom.activeUsersLimit) {
return sails.getDatastore().transaction(async (db) => {
const queryResult = await sails
.sendNativeQuery('SELECT NULL FROM user_account WHERE is_deactivated = $1 FOR UPDATE', [
false,
])
.usingConnection(db);
if (queryResult.rowCount >= sails.config.custom.activeUsersLimit) {
throw 'activeLimitReached';
}
return User.create({ ...values })
.fetch()
.usingConnection(db);
});
}
return User.create({ ...values }).fetch();
};
const getByIds = (ids) => defaultFind(ids);
const getAll = ({ roleOrRoles } = {}) =>
defaultFind({
role: roleOrRoles,
});
const getOneById = (id, { withDeactivated = true } = {}) => {
const criteria = {
id,
};
if (!withDeactivated) {
criteria.isDeactivated = false;
}
return User.findOne(criteria);
};
const getOneByEmail = (email) =>
User.findOne({
email: email.toLowerCase(),
});
const getOneActiveByEmailOrUsername = (emailOrUsername) => {
const fieldName = emailOrUsername.includes('@') ? 'email' : 'username';
return User.findOne({
[fieldName]: emailOrUsername.toLowerCase(),
isDeactivated: false,
});
};
const updateOne = (criteria, values) => {
if (values.isDeactivated === false && sails.config.custom.activeUsersLimit) {
return sails.getDatastore().transaction(async (db) => {
const queryResult = await sails
.sendNativeQuery('SELECT NULL FROM user_account WHERE is_deactivated = $1 FOR UPDATE', [
false,
])
.usingConnection(db);
if (queryResult.rowCount >= sails.config.custom.activeUsersLimit) {
throw 'activeLimitReached';
}
return User.updateOne(criteria)
.set({ ...values })
.usingConnection(db);
});
}
return User.updateOne(criteria).set({ ...values });
};
const deleteOne = (criteria) => User.destroyOne(criteria);
module.exports = {
createOne,
getByIds,
getAll,
getOneById,
getOneByEmail,
getOneActiveByEmailOrUsername,
updateOne,
deleteOne,
};