mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 21:27:23 +01:00
Group managers (#8591)
* Added abiltiy to add group managers * Added ability to remove managers * Added ability for managers to add group tasks * Allower managers to assign tasks * Allowed managers to unassign tasks * Allow managers to delete group tasks * Allowed managers to approve * Added initial ui * Added approval view for managers * Allowed managers to edit * Fixed lint issues * Added spacing to buttons * Removed leader from selection of group managers * Code review updates * Ensured approvals are only done once * Added ability for parties to add managers * Add notifications to all managers when approval is requests * Removed tasks need approval notifications from all managers when task is approve * Fixed linting issues * Hid add managers UI from groups that are not subscribed * Removed let from front end * Fixed issues with post task url params * Fixed string locales * Removed extra limited strings * Added cannotedit tasks function * Added limit fields and notification check by taskId * Localized string and other minor issues * Added manager and leader indicator * Added group notifications refresh on sync * Added close button for group notifications * Removed group approval notifications when manager is removed * Moved leader/manager indicators to after hp * Added manager fields to groups * Spelling and syntax fixes
This commit is contained in:
@@ -25,6 +25,13 @@ import logger from '../../libs/logger';
|
||||
|
||||
const MAX_SCORE_NOTES_LENGTH = 256;
|
||||
|
||||
function canNotEditTasks (group, user, assignedUserId) {
|
||||
let isNotGroupLeader = group.leader !== user._id;
|
||||
let isManager = Boolean(group.managers[user._id]);
|
||||
let userIsAssigningToSelf = Boolean(assignedUserId && user._id === assignedUserId);
|
||||
return isNotGroupLeader && !isManager && !userIsAssigningToSelf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @apiDefine TaskNotFound
|
||||
* @apiError (404) {NotFound} TaskNotFound The specified task could not be found.
|
||||
@@ -413,9 +420,10 @@ api.updateTask = {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
// @TODO: Abstract this access snippet
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
} else if (task.challenge.id && !task.userId) { // If the task belongs to a challenge make sure the user has rights
|
||||
challenge = await Challenge.findOne({_id: task.challenge.id}).exec();
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
@@ -530,18 +538,29 @@ api.scoreTask = {
|
||||
task.group.approval.requested = true;
|
||||
task.group.approval.requestedDate = new Date();
|
||||
|
||||
let group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
let groupLeader = await User.findById(group.leader).exec(); // Use this method so we can get access to notifications
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
let group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
|
||||
groupLeader.addNotification('GROUP_TASK_APPROVAL', {
|
||||
message: res.t('userHasRequestedTaskApproval', {
|
||||
user: user.profile.name,
|
||||
taskName: task.text,
|
||||
}, groupLeader.preferences.language),
|
||||
groupId: group._id,
|
||||
// @TODO: we can use the User.pushNotification function because we need to ensure notifications are translated
|
||||
let managerIds = Object.keys(group.managers);
|
||||
managerIds.push(group.leader);
|
||||
let managers = await User.find({_id: managerIds}, 'notifications preferences').exec(); // Use this method so we can get access to notifications
|
||||
|
||||
let managerPromises = [];
|
||||
managers.forEach((manager) => {
|
||||
manager.addNotification('GROUP_TASK_APPROVAL', {
|
||||
message: res.t('userHasRequestedTaskApproval', {
|
||||
user: user.profile.name,
|
||||
taskName: task.text,
|
||||
}, manager.preferences.language),
|
||||
groupId: group._id,
|
||||
taskId: task._id,
|
||||
});
|
||||
managerPromises.push(manager.save());
|
||||
});
|
||||
|
||||
await Bluebird.all([groupLeader.save(), task.save()]);
|
||||
managerPromises.push(task.save());
|
||||
await Bluebird.all(managerPromises);
|
||||
|
||||
throw new NotAuthorized(res.t('taskApprovalHasBeenRequested'));
|
||||
}
|
||||
@@ -694,9 +713,9 @@ api.addChecklistItem = {
|
||||
if (!task) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
} else if (task.challenge.id && !task.userId) { // If the task belongs to a challenge make sure the user has rights
|
||||
challenge = await Challenge.findOne({_id: task.challenge.id}).exec();
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
@@ -803,9 +822,10 @@ api.updateChecklistItem = {
|
||||
if (!task) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
} else if (task.challenge.id && !task.userId) { // If the task belongs to a challenge make sure the user has rights
|
||||
challenge = await Challenge.findOne({_id: task.challenge.id}).exec();
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
@@ -867,9 +887,10 @@ api.removeChecklistItem = {
|
||||
if (!task) {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
} else if (task.challenge.id && !task.userId) { // If the task belongs to a challenge make sure the user has rights
|
||||
challenge = await Challenge.findOne({_id: task.challenge.id}).exec();
|
||||
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
|
||||
@@ -1185,9 +1206,10 @@ api.deleteTask = {
|
||||
throw new NotFound(res.t('taskNotFound'));
|
||||
} else if (task.group.id && !task.userId) {
|
||||
// @TODO: Abstract this access snippet
|
||||
let group = await Group.getGroup({user, groupId: task.group.id, fields: requiredGroupFields});
|
||||
let fields = requiredGroupFields.concat(' managers');
|
||||
let group = await Group.getGroup({user, groupId: task.group.id, fields});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
if (group.leader !== user._id) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
|
||||
await group.removeTask(task);
|
||||
} else if (task.challenge.id && !task.userId) { // If the task belongs to a challenge make sure the user has rights
|
||||
challenge = await Challenge.findOne({_id: task.challenge.id}).exec();
|
||||
|
||||
Reference in New Issue
Block a user