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

@ -1,89 +1,230 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
const { idInput } = require('../../../utils/inputs');
const Errors = {
NOT_ENOUGH_RIGHTS: {
notEnoughRights: 'Not enough rights',
},
PROJECT_NOT_FOUND: {
projectNotFound: 'Project not found',
},
OWNER_PROJECT_MANAGER_NOT_FOUND: {
ownerProjectManagerNotFound: 'Owner project manager not found',
},
BACKGROUND_IMAGE_NOT_FOUND: {
backgroundImageNotFound: 'Background image not found',
},
PROJECT_ALREADY_HAS_OWNER_PROJECT_MANAGER: {
projectAlreadyHasOwnerProjectManager: 'Project already has owner project manager',
},
OWNER_PROJECT_MANAGER_MUST_BE_LAST_MANAGER: {
ownerProjectManagerMustBeLastManager: 'Owner project manager must be last manager',
},
BACKGROUND_IMAGE_MUST_BE_PRESENT: {
backgroundImageMustBePresent: 'Background image must be present',
},
BACKGROUND_GRADIENT_MUST_BE_PRESENT: {
backgroundGradientMustBePresent: 'Background gradient must be present',
},
};
const backgroundValidator = (value) => {
if (_.isNull(value)) {
return true;
}
if (!_.isPlainObject(value)) {
return false;
}
if (!Object.values(Project.BackgroundTypes).includes(value.type)) {
return false;
}
if (
value.type === Project.BackgroundTypes.GRADIENT &&
_.size(value) === 2 &&
Project.BACKGROUND_GRADIENTS.includes(value.name)
) {
return true;
}
if (value.type === Project.BackgroundTypes.IMAGE && _.size(value) === 1) {
return true;
}
return false;
};
const backgroundImageValidator = (value) => _.isNull(value);
module.exports = {
inputs: {
id: {
type: 'string',
regex: /^[0-9]+$/,
...idInput,
required: true,
},
ownerProjectManagerId: {
...idInput,
allowNull: true,
},
backgroundImageId: {
...idInput,
allowNull: true,
},
name: {
type: 'string',
isNotEmptyString: true,
maxLength: 128,
},
background: {
type: 'json',
custom: backgroundValidator,
description: {
type: 'string',
isNotEmptyString: true,
maxLength: 1024,
allowNull: true,
},
backgroundImage: {
type: 'json',
custom: backgroundImageValidator,
backgroundType: {
type: 'string',
isIn: Object.values(Project.BackgroundTypes),
allowNull: true,
},
backgroundGradient: {
type: 'string',
isIn: Project.BACKGROUND_GRADIENTS,
allowNull: true,
},
isHidden: {
type: 'boolean',
},
isFavorite: {
type: 'boolean',
},
},
exits: {
notEnoughRights: {
responseType: 'forbidden',
},
projectNotFound: {
responseType: 'notFound',
},
ownerProjectManagerNotFound: {
responseType: 'notFound',
},
backgroundImageNotFound: {
responseType: 'notFound',
},
projectAlreadyHasOwnerProjectManager: {
responseType: 'conflict',
},
ownerProjectManagerMustBeLastManager: {
responseType: 'unprocessableEntity',
},
backgroundImageMustBePresent: {
responseType: 'unprocessableEntity',
},
backgroundGradientMustBePresent: {
responseType: 'unprocessableEntity',
},
},
async fn(inputs) {
const { currentUser } = this.req;
let project = await Project.findOne(inputs.id);
let project = await Project.qm.getOneById(inputs.id);
if (!project) {
throw Errors.PROJECT_NOT_FOUND;
}
const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id);
const projectManager = await ProjectManager.qm.getOneByProjectIdAndUserId(
project.id,
currentUser.id,
);
if (!isProjectManager) {
throw Errors.PROJECT_NOT_FOUND; // Forbidden
const availableInputKeys = ['id', 'isFavorite'];
if (project.ownerProjectManagerId) {
if (projectManager) {
if (!_.isNil(inputs.ownerProjectManagerId)) {
throw Errors.NOT_ENOUGH_RIGHTS;
}
availableInputKeys.push('ownerProjectManagerId', 'isHidden');
}
} else if (currentUser.role === User.Roles.ADMIN) {
availableInputKeys.push('ownerProjectManagerId', 'isHidden');
} else if (projectManager) {
availableInputKeys.push('isHidden');
}
const values = _.pick(inputs, ['name', 'background', 'backgroundImage']);
if (projectManager) {
availableInputKeys.push(
'backgroundImageId',
'name',
'description',
'backgroundType',
'backgroundGradient',
);
}
project = await sails.helpers.projects.updateOne.with({
values,
record: project,
actorUser: currentUser,
request: this.req,
});
if (_.difference(Object.keys(inputs), availableInputKeys).length > 0) {
throw Errors.NOT_ENOUGH_RIGHTS;
}
let nextOwnerProjectManager;
if (inputs.ownerProjectManagerId) {
nextOwnerProjectManager = await ProjectManager.qm.getOneById(inputs.ownerProjectManagerId, {
projectId: project.id,
});
if (!nextOwnerProjectManager) {
throw Errors.OWNER_PROJECT_MANAGER_NOT_FOUND;
}
delete inputs.ownerProjectManagerId; // eslint-disable-line no-param-reassign
}
let nextBackgroundImage;
if (inputs.backgroundImageId) {
nextBackgroundImage = await BackgroundImage.qm.getOneById(inputs.backgroundImageId, {
projectId: project.id,
});
if (!nextBackgroundImage) {
throw Errors.BACKGROUND_IMAGE_NOT_FOUND;
}
delete inputs.backgroundImageId; // eslint-disable-line no-param-reassign
}
if (!_.isUndefined(inputs.isFavorite)) {
if (currentUser.role !== User.Roles.ADMIN || project.ownerProjectManagerId) {
if (!projectManager) {
const boardMembershipsTotal =
await sails.helpers.projects.getBoardMembershipsTotalByIdAndUserId(
project.id,
currentUser.id,
);
if (boardMembershipsTotal === 0) {
throw Errors.PROJECT_NOT_FOUND; // Forbidden
}
}
}
}
const values = _.pick(inputs, [
'ownerProjectManagerId',
'backgroundImageId',
'name',
'description',
'backgroundType',
'backgroundGradient',
'isHidden',
'isFavorite',
]);
project = await sails.helpers.projects.updateOne
.with({
record: project,
values: {
...values,
ownerProjectManager: nextOwnerProjectManager,
backgroundImage: nextBackgroundImage,
},
actorUser: currentUser,
request: this.req,
})
.intercept(
'ownerProjectManagerInValuesMustBeLastManager',
() => Errors.OWNER_PROJECT_MANAGER_MUST_BE_LAST_MANAGER,
)
.intercept(
'backgroundImageInValuesMustBePresent',
() => Errors.BACKGROUND_IMAGE_MUST_BE_PRESENT,
)
.intercept(
'backgroundGradientInValuesMustBePresent',
() => Errors.BACKGROUND_GRADIENT_MUST_BE_PRESENT,
)
.intercept(
'alreadyHasOwnerProjectManager',
() => Errors.PROJECT_ALREADY_HAS_OWNER_PROJECT_MANAGER,
);
if (!project) {
throw Errors.PROJECT_NOT_FOUND;