diff --git a/website/client/src/components/tasks/task.vue b/website/client/src/components/tasks/task.vue index 963c3f85f0..59426dcc1c 100644 --- a/website/client/src/components/tasks/task.vue +++ b/website/client/src/components/tasks/task.vue @@ -3,9 +3,9 @@
@@ -16,8 +16,7 @@ />
@@ -1048,12 +1038,26 @@ export default { }, teamManagerAccess () { if (!this.isGroupTask || !this.group) return true; + if (!this.group.leader && !this.group.managers) return false; return (this.group.leader._id === this.user._id || this.group.managers[this.user._id]); }, displayNotes () { if (this.isGroupTask && !this.isUser) return this.task.group.managerNotes; return this.task.notes; }, + isOpenTask () { + if (!this.isGroupTask) return false; + if (this.task.group.assignedUsers.length > 0) return false; + return true; + }, + showTaskLockIcon () { + if (this.isUser) return false; + if (this.isGroupTask) { + if (this.isOpenTask) return false; + if (this.task.group.assignedUsers.indexOf(this.user._id) !== -1) return false; + } + return true; + }, }, methods: { ...mapActions({ @@ -1121,6 +1125,8 @@ export default { setTimeout(() => this.$root.$emit('castEnd', task, 'task', e), 0); }, async score (direction) { + if (this.showTaskLockIcon) return; + if (this.task.type === 'habit' && !this.task[direction]) return; if (this.isYesterdaily === true) { await this.beforeTaskScore(this.task); this.task.completed = !this.task.completed; diff --git a/website/client/src/components/tasks/yesterdailyModal.vue b/website/client/src/components/tasks/yesterdailyModal.vue index 0a24fbac8a..1c12e39fb8 100644 --- a/website/client/src/components/tasks/yesterdailyModal.vue +++ b/website/client/src/components/tasks/yesterdailyModal.vue @@ -84,6 +84,7 @@ import moment from 'moment'; import { mapState } from '@/libs/store'; import scoreTask from '@/mixins/scoreTask'; +import sync from '@/mixins/sync'; import Task from './task'; import LoadingSpinner from '../ui/loadingSpinner'; @@ -92,7 +93,7 @@ export default { Task, LoadingSpinner, }, - mixins: [scoreTask], + mixins: [scoreTask, sync], props: { yesterDailies: { type: Array, @@ -180,6 +181,7 @@ export default { this.isLoading = false; this.$root.$emit('bv::hide::modal', 'yesterdaily'); + if (this.$route.fullPath.indexOf('task-information') !== -1) this.sync(); }, }, }; diff --git a/website/client/src/store/getters/tasks.js b/website/client/src/store/getters/tasks.js index 525ffbdb26..a194f385b1 100644 --- a/website/client/src/store/getters/tasks.js +++ b/website/client/src/store/getters/tasks.js @@ -114,15 +114,20 @@ export function canEdit (store) { }; } -function _nonInteractive (task) { - return (task.group && task.group.id && !task.userId) - || (task.challenge && task.challenge.id && !task.userId) - || (task.group && task.group.approval && task.group.approval.requested - && task.type !== 'habit'); +function _nonInteractive (task, userId) { + if (task.userId) return false; + if (task.challenge && task.challenge.id) return true; + if ( + task.group + && task.group.assignedUsers.length > 0 + && task.group.assignedUsers.indexOf(userId) === -1 + ) return true; + return false; } export function getTaskClasses (store) { const userPreferences = store.state.user.data.preferences; + const userId = store.state.user.data._id; // Purpose can be one of the following strings: // Edit Modal: edit-modal-bg, edit-modal-text, edit-modal-icon @@ -171,7 +176,7 @@ export function getTaskClasses (store) { if (type === 'todo' || type === 'daily') { if (task.completed || (!shouldDo(dueDate, task, userPreferences) && type === 'daily')) { return { - bg: _nonInteractive(task) ? 'task-disabled-daily-todo-control-bg-noninteractive' : 'task-disabled-daily-todo-control-bg', + bg: _nonInteractive(task, userId) ? 'task-disabled-daily-todo-control-bg-noninteractive' : 'task-disabled-daily-todo-control-bg', checkbox: 'task-disabled-daily-todo-control-checkbox', inner: 'task-disabled-daily-todo-control-inner', content: 'task-disabled-daily-todo-control-content', @@ -179,28 +184,28 @@ export function getTaskClasses (store) { } return { - bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, + bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, checkbox: `task-${color}-control-checkbox`, inner: `task-${color}-control-inner-daily-todo`, icon: `task-${color}-control-icon`, }; } if (type === 'reward') { return { - bg: _nonInteractive(task) ? 'task-reward-control-bg-noninteractive' : 'task-reward-control-bg', + bg: _nonInteractive(task, userId) ? 'task-reward-control-bg-noninteractive' : 'task-reward-control-bg', }; } if (type === 'habit') { return { up: task.up ? { - bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, - inner: _nonInteractive(task) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`, + bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, + inner: _nonInteractive(task, userId) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`, icon: `task-${color}-control-icon`, } : { bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner', icon: `task-${color}-control-icon` }, down: task.down ? { - bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, - inner: _nonInteractive(task) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`, + bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`, + inner: _nonInteractive(task, userId) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`, icon: `task-${color}-control-icon`, } : { bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner', icon: `task-${color}-control-icon` }, diff --git a/website/common/script/ops/scoreTask.js b/website/common/script/ops/scoreTask.js index 59645e4b71..708ce1d5f8 100644 --- a/website/common/script/ops/scoreTask.js +++ b/website/common/script/ops/scoreTask.js @@ -104,7 +104,7 @@ function _gainMP (user, val) { // ===== CONSTITUTION ===== // TODO Decreases HP loss from bad habits / missed dailies by 0.5% per point. function _subtractPoints (user, task, stats, delta) { - if (task.group.id && !task.userId) return stats.hp; + if (task.group.id && !task.userId && task.type === 'daily') return stats.hp; let conBonus = 1 - statsComputed(user).con / 250; if (conBonus < 0.1) conBonus = 0.1; diff --git a/website/server/controllers/api-v3/tasks.js b/website/server/controllers/api-v3/tasks.js index 5c20a9f4d7..d6aa1cb958 100644 --- a/website/server/controllers/api-v3/tasks.js +++ b/website/server/controllers/api-v3/tasks.js @@ -654,13 +654,6 @@ api.updateTask = { // the other of the keys when using .toObject() // see https://github.com/Automattic/mongoose/issues/2749 - task.group.approval.required = false; - if (sanitizedObj.requiresApproval) { - task.group.approval.required = true; - } - if (sanitizedObj.sharedCompletion) { - task.group.sharedCompletion = sanitizedObj.sharedCompletion; - } if (sanitizedObj.managerNotes) { task.group.managerNotes = sanitizedObj.managerNotes; } diff --git a/website/server/controllers/api-v3/tasks/groups.js b/website/server/controllers/api-v3/tasks/groups.js index 98da938496..e78735e588 100644 --- a/website/server/controllers/api-v3/tasks/groups.js +++ b/website/server/controllers/api-v3/tasks/groups.js @@ -208,26 +208,13 @@ api.assignTask = { const group = await Group.getGroup({ user, groupId: task.group.id, fields: groupFields }); if (!group) throw new NotFound(res.t('groupNotFound')); - if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks')); + if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks')); const promises = []; const taskText = task.text; const userName = `@${user.auth.local.username}`; - if (user._id === assignedUserId) { - const managerIds = Object.keys(group.managers); - managerIds.push(group.leader); - const managers = await User.find({ _id: managerIds }, 'notifications preferences').exec(); - managers.forEach(manager => { - if (manager._id === user._id) return; - manager.addNotification('GROUP_TASK_CLAIMED', { - message: res.t('taskClaimed', { userName, taskText }, manager.preferences.language), - groupId: group._id, - taskId: task._id, - }); - promises.push(manager.save()); - }); - } else { + if (user._id !== assignedUserId) { assignedUser.addNotification('GROUP_TASK_ASSIGNED', { message: res.t('youHaveBeenAssignedTask', { managerName: userName, taskText }), taskId: task._id, @@ -283,7 +270,7 @@ api.unassignTask = { const group = await Group.getGroup({ user, groupId: task.group.id, fields }); if (!group) throw new NotFound(res.t('groupNotFound')); - if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks')); + if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks')); await group.unlinkTask(task, assignedUser); @@ -531,7 +518,7 @@ api.getGroupApprovals = { if (canNotEditTasks(group, user)) { approvals = await Tasks.Task.find({ 'group.id': groupId, - 'group.approval.approved': false, + 'group.approval.approved': { $ne: true }, 'group.approval.requested': true, 'group.assignedUsers': user._id, userId: user._id, @@ -541,7 +528,7 @@ api.getGroupApprovals = { } else { approvals = await Tasks.Task.find({ 'group.id': groupId, - 'group.approval.approved': false, + 'group.approval.approved': { $ne: true }, 'group.approval.requested': true, }, 'userId group text') .populate('userId', 'profile') diff --git a/website/server/models/task.js b/website/server/models/task.js index 604de20ca9..1b40940f4c 100644 --- a/website/server/models/task.js +++ b/website/server/models/task.js @@ -216,8 +216,6 @@ TaskSchema.statics.findMultipleByIdOrAlias = async function findByIdOrAlias ( if (!userId) throw new Error('User identifier is a required argument'); const query = _.cloneDeep(additionalQueries); - query.userId = userId; - const ids = []; const aliases = []; @@ -229,10 +227,18 @@ TaskSchema.statics.findMultipleByIdOrAlias = async function findByIdOrAlias ( } }); - query.$or = [ - { _id: { $in: ids } }, - { alias: { $in: aliases } }, - ]; + if (ids.length > 0 && aliases.length > 0) { + query.$or = [ + { _id: { $in: ids } }, + { alias: { $in: aliases } }, + ]; + } else if (ids.length > 0) { + query._id = { $in: ids }; + } else if (aliases.length > 0) { + query.alias = { $in: aliases }; + } else { + throw new Error('No identifiers found.'); // Should be covered by the !identifiers check, but.. + } const tasks = await this.find(query).exec();