mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-21 05:08:51 +00:00
Squashed commit of the following:
commit 0db0a69f0fa00d831b7d90340e045097e8d92343
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jul 16 10:01:49 2019 -0500
fix(groups): return 0, not empty, when skipping downscore on Dailies
fixes #11231
commit 1bf5bc714f660345f37bcc4e3587143341521c65
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jul 16 09:48:28 2019 -0500
fix(groups): correct task creation button
commit 90908211200bc4a3eb204178df5c812ffcd09f37
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jul 16 09:46:04 2019 -0500
fix(groups): clear approval status at cron for Habits and Dailies
commit 57e8dd0252c3ea45dd6fa1a7670ee197f32e76e5
Merge: d31b0a2d0 c9a56e8f3
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jul 16 09:33:27 2019 -0500
Merge branch 'develop' into sabrecat/group-tasks
commit d31b0a2d0e3b7a46235696e9b05fa734ac29a2e5
Merge: f2185a91b 043696c22
Author: SabreCat <sabrecat@gmail.com>
Date: Mon Jun 24 14:58:26 2019 +0000
Merge branch 'develop' into sabrecat/group-tasks
commit f2185a91bde554c7eb22cd6bdfc1ef9227f1e765
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jun 18 10:10:10 2019 -0500
fix(groups): divide task delta by number of assigned users
commit af0cde52f22129312d0102ecc5571f59aa2e396e
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jun 18 10:06:01 2019 -0500
fix(groups): remove chat spam
commit c1c810967a9e34155948a9164862125517372268
Merge: bf4f3fb08 f987585cf
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue Jun 18 08:15:28 2019 -0500
Merge branch 'develop' into sabrecat/group-tasks
commit bf4f3fb08491b4c4e1dbfaa58a2a6510c3cb78aa
Author: Sabe Jones <sabrecat@gmail.com>
Date: Thu May 23 11:29:01 2019 -0500
fix(test): expect new task class from store
commit ae0379c80519523f68d4d606e1cc4bed8e9e49ec
Merge: ce5096e11 664cf5a47
Author: Sabe Jones <sabrecat@gmail.com>
Date: Thu May 23 11:25:15 2019 -0500
Merge branch 'develop' into sabrecat/group-tasks
commit ce5096e116558419e4a73e8b23a58c78a1f2ab9b
Author: Sabe Jones <sabrecat@gmail.com>
Date: Thu May 23 11:02:01 2019 -0500
feat(group-plans): clarify non-interactive controls on task board
commit ff3cec9530e30d51c43171d6f97d3888ff200352
Author: Sabe Jones <sabrecat@gmail.com>
Date: Tue May 21 11:10:50 2019 -0500
feat(group-plans): score shared task when user scores it
This commit is contained in:
parent
8702a28bcc
commit
07ae4134f3
12 changed files with 91 additions and 49 deletions
|
|
@ -93,15 +93,6 @@ describe('POST /tasks/:taskId/assign/:memberId', () => {
|
|||
expect(syncedTask).to.exist;
|
||||
});
|
||||
|
||||
it('sends a message to the group when a user claims a task', async () => {
|
||||
await member.post(`/tasks/${task._id}/assign/${member._id}`);
|
||||
|
||||
let updateGroup = await user.get(`/groups/${guild._id}`);
|
||||
|
||||
expect(updateGroup.chat[0].text).to.equal(t('userIsClamingTask', {username: member.profile.name, task: task.text}));
|
||||
expect(updateGroup.chat[0].uuid).to.equal('system');
|
||||
});
|
||||
|
||||
it('assigns a task to a user', async () => {
|
||||
await user.post(`/tasks/${task._id}/assign/${member._id}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -131,10 +131,12 @@ describe('getTaskClasses getter', () => {
|
|||
up: {
|
||||
bg: 'task-good-control-bg',
|
||||
inner: 'task-good-control-inner-habit',
|
||||
icon: 'task-good-control-icon',
|
||||
},
|
||||
down: {
|
||||
bg: 'task-disabled-habit-control-bg',
|
||||
inner: 'task-disabled-habit-control-inner',
|
||||
icon: 'task-good-control-icon',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.task {
|
||||
&-worst { // dark red
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $maroon-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: $maroon-500 !important; }
|
||||
&-checkbox { color: $maroon-100 !important; }
|
||||
&-icon { color: #6c0406 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
|
|
@ -30,7 +31,7 @@
|
|||
|
||||
&-worse { // light red
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $red-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: $red-500 !important; }
|
||||
&-checkbox { color: $red-100 !important; }
|
||||
&-icon { color: #6c0406 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
|
|
@ -59,7 +61,7 @@
|
|||
|
||||
&-bad { // orange
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $orange-100 !important;
|
||||
|
||||
&:hover {
|
||||
|
|
@ -70,10 +72,11 @@
|
|||
&-inner-habit { background: rgba(183, 90, 28, 0.4) !important; }
|
||||
&-inner-daily-todo { background: $orange-500 !important; }
|
||||
&-checkbox { color: $orange-100 !important; }
|
||||
&-icon { color: #7f3300 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $orange-100 !important;
|
||||
|
||||
.form-control {
|
||||
|
|
@ -99,7 +102,7 @@
|
|||
|
||||
&-neutral { // yellow
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $yellow-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: #bf7d1a !important; }
|
||||
|
|
@ -109,10 +112,11 @@
|
|||
&-inner-habit { background: rgba(183, 90, 28, 0.32) !important; }
|
||||
&-inner-daily-todo { background: $yellow-500 !important; }
|
||||
&-checkbox { color: $yellow-100 !important; }
|
||||
&-icon { color: #794b00 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $yellow-100 !important;
|
||||
|
||||
.form-control {
|
||||
|
|
@ -138,7 +142,7 @@
|
|||
|
||||
&-good { // green
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $green-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
|
|
@ -148,6 +152,7 @@
|
|||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: #77f4c7 !important; }
|
||||
&-checkbox { color: $green-10 !important; }
|
||||
&-icon { color: #005737 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
|
|
@ -167,7 +172,7 @@
|
|||
|
||||
&-better { // teal
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $teal-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
|
|
@ -177,6 +182,7 @@
|
|||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: #8dedf6 !important; }
|
||||
&-checkbox { color: $teal-100 !important; }
|
||||
&-icon { color: #005158 !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
|
|
@ -196,7 +202,7 @@
|
|||
|
||||
&-best { // blue
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $blue-100 !important;
|
||||
&:hover {
|
||||
.habit-control { background: rgba(26, 24, 29, 0.48) !important; }
|
||||
|
|
@ -206,6 +212,7 @@
|
|||
&-inner-habit { background: rgba(26, 24, 29, 0.24) !important; }
|
||||
&-inner-daily-todo { background: $blue-500 !important; }
|
||||
&-checkbox { color: $blue-100 !important; }
|
||||
&-icon { color: #033f5e !important; }
|
||||
}
|
||||
|
||||
&-modal {
|
||||
|
|
@ -241,7 +248,7 @@
|
|||
|
||||
&-reward {
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: rgba(255, 217, 160, 0.32) !important;
|
||||
.small-text { color: $orange-10 !important; }
|
||||
|
||||
|
|
@ -251,7 +258,7 @@
|
|||
}
|
||||
|
||||
&-disabled {
|
||||
&-habit {
|
||||
&-habit {
|
||||
&-control {
|
||||
&-bg { background: $gray-600; }
|
||||
&-inner {
|
||||
|
|
@ -261,13 +268,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
&-daily-todo {
|
||||
&-daily-todo {
|
||||
&-control {
|
||||
&-bg {
|
||||
&-bg {
|
||||
background: $gray-400 !important;
|
||||
&:hover {
|
||||
.daily-todo-control { background: rgba(255, 255, 255, 0.72) !important; }
|
||||
}
|
||||
}
|
||||
}
|
||||
&-inner { background: $gray-500 !important; }
|
||||
&-checkbox { color: $gray-400 !important; }
|
||||
|
|
@ -298,6 +305,12 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.lock {
|
||||
margin-top: 7px;
|
||||
height: 12px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.positive {
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
|
@ -321,4 +334,10 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-icon.lock {
|
||||
margin: 8px auto;
|
||||
height: 12px;
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="12" viewBox="0 0 10 12">
|
||||
<path fill="#C3C0C7" fill-rule="evenodd" d="M4 9h2V7H4v2zm4 1H2V6h6v4zM5 2c1.103 0 2 .897 2 2H3c0-1.103.897-2 2-2zm4 2.277V4a4 4 0 0 0-8 0v.277C.405 4.624 0 5.262 0 6v4a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6c0-.738-.405-1.376-1-1.723z"/>
|
||||
<path fill-rule="evenodd" d="M4 9h2V7H4v2zm4 1H2V6h6v4zM5 2c1.103 0 2 .897 2 2H3c0-1.103.897-2 2-2zm4 2.277V4a4 4 0 0 0-8 0v.277C.405 4.624 0 5.262 0 6v4a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6c0-.738-.405-1.376-1-1.723z"/>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 311 B |
|
|
@ -6,11 +6,13 @@
|
|||
// Habits left side control
|
||||
.left-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.up.bg")
|
||||
.task-control.habit-control(:class="controlClass.up.inner", @click="(isUser && task.up) ? score('up') : null")
|
||||
.svg-icon.positive(v-html="icons.positive")
|
||||
.svg-icon.lock(v-if="this.task.group.id && !isUser", v-html="icons.lock", :class="controlClass.up.icon")
|
||||
.svg-icon.positive(v-else, v-html="icons.positive")
|
||||
// Dailies and todos left side control
|
||||
.left-control.d-flex.justify-content-center(v-if="task.type === 'daily' || task.type === 'todo'", :class="controlClass.bg")
|
||||
.task-control.daily-todo-control(:class="controlClass.inner", @click="isUser ? score(task.completed ? 'down' : 'up') : null")
|
||||
.svg-icon.check(v-html="icons.check", :class="{'display-check-icon': task.completed, [controlClass.checkbox]: true}")
|
||||
.svg-icon.lock(v-html="icons.lock", v-if="this.task.group.id && !isUser && !task.completed", :class="controlClass.icon")
|
||||
.svg-icon.check(v-else, v-html="icons.check", :class="{'display-check-icon': task.completed, [controlClass.checkbox]: true}")
|
||||
// Task title, description and icons
|
||||
.task-content(:class="contentClass")
|
||||
.task-clickable-area(@click="edit($event, task)", :class="{'task-clickable-area-user': isUser}")
|
||||
|
|
@ -99,7 +101,8 @@
|
|||
// Habits right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.down.bg")
|
||||
.task-control.habit-control(:class="controlClass.down.inner", @click="(isUser && task.down) ? score('down') : null")
|
||||
.svg-icon.negative(v-html="icons.negative")
|
||||
.svg-icon.lock(v-if="this.task.group.id && !isUser", v-html="icons.lock", :class="controlClass.down.icon")
|
||||
.svg-icon.negative(v-else, v-html="icons.negative")
|
||||
// Rewards right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center.reward-control(v-if="task.type === 'reward'", :class="controlClass.bg", @click="isUser ? score('down') : null")
|
||||
.svg-icon(v-html="icons.gold")
|
||||
|
|
@ -533,6 +536,7 @@ import topIcon from 'assets/svg/top.svg';
|
|||
import bottomIcon from 'assets/svg/bottom.svg';
|
||||
import deleteIcon from 'assets/svg/delete.svg';
|
||||
import checklistIcon from 'assets/svg/checklist.svg';
|
||||
import lockIcon from 'assets/svg/lock.svg';
|
||||
import menuIcon from 'assets/svg/menu.svg';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
|
|
@ -569,6 +573,7 @@ export default {
|
|||
top: topIcon,
|
||||
bottom: bottomIcon,
|
||||
menu: menuIcon,
|
||||
lock: lockIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ export function getTaskClasses (store) {
|
|||
bg: `task-${color}-control-bg`,
|
||||
checkbox: `task-${color}-control-checkbox`,
|
||||
inner: `task-${color}-control-inner-daily-todo`,
|
||||
icon: `task-${color}-control-icon`,
|
||||
};
|
||||
} else if (type === 'reward') {
|
||||
return {
|
||||
|
|
@ -102,11 +103,11 @@ export function getTaskClasses (store) {
|
|||
} else if (type === 'habit') {
|
||||
return {
|
||||
up: task.up ?
|
||||
{ bg: `task-${color}-control-bg`, inner: `task-${color}-control-inner-habit`} :
|
||||
{ bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner' },
|
||||
{ bg: `task-${color}-control-bg`, inner: `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: `task-${color}-control-bg`, inner: `task-${color}-control-inner-habit`} :
|
||||
{ bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner' },
|
||||
{ bg: `task-${color}-control-bg`, inner: `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` },
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ module.exports = function scoreTask (options = {}, req = {}) {
|
|||
exp: user.stats.exp,
|
||||
};
|
||||
|
||||
if (task.group && task.group.approval && task.group.approval.required && !task.group.approval.approved) return;
|
||||
if (task.group && task.group.approval && task.group.approval.required && !task.group.approval.approved) return 0;
|
||||
|
||||
// This is for setting one-time temporary flags, such as streakBonus or itemDropped. Useful for notifying
|
||||
// the API consumer, then cleared afterwards
|
||||
|
|
|
|||
|
|
@ -638,6 +638,18 @@ api.scoreTask = {
|
|||
|
||||
if (task.group && task.group.taskId) {
|
||||
await handleSharedCompletion(task);
|
||||
try {
|
||||
const groupTask = await Tasks.Task.findOne({
|
||||
_id: task.group.taskId,
|
||||
}).exec();
|
||||
|
||||
if (groupTask) {
|
||||
const groupDelta = groupTask.group.assignedUsers ? delta / groupTask.group.assignedUsers.length : delta;
|
||||
await groupTask.scoreChallengeTask(groupDelta, direction);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Save results and handle request
|
||||
|
|
|
|||
|
|
@ -201,19 +201,7 @@ api.assignTask = {
|
|||
|
||||
let promises = [];
|
||||
|
||||
// User is claiming the task
|
||||
if (user._id === assignedUserId) {
|
||||
let message = res.t('userIsClamingTask', {username: user.profile.name, task: task.text});
|
||||
const newMessage = group.sendChat({
|
||||
message,
|
||||
info: {
|
||||
type: 'claim_task',
|
||||
user: user.profile.name,
|
||||
task: task.text,
|
||||
},
|
||||
});
|
||||
promises.push(newMessage.save());
|
||||
} else {
|
||||
if (user._id !== assignedUserId) {
|
||||
const taskText = task.text;
|
||||
const managerName = user.profile.name;
|
||||
|
||||
|
|
|
|||
|
|
@ -389,6 +389,13 @@ export function cron (options = {}) {
|
|||
task.checklist.forEach(i => i.completed = false);
|
||||
}
|
||||
}
|
||||
|
||||
if (task.group && task.group.approval && task.group.approval.approved) {
|
||||
task.group.approval.approved = false;
|
||||
task.group.approval.dateApproved = null;
|
||||
task.group.approval.requested = false;
|
||||
task.group.approval.requestedDate = null;
|
||||
}
|
||||
});
|
||||
|
||||
resetHabitCounters(user, tasksByType, now, daysMissed);
|
||||
|
|
@ -399,6 +406,12 @@ export function cron (options = {}) {
|
|||
if (task.up === false || task.down === false) {
|
||||
task.value = Math.abs(task.value) < 0.1 ? 0 : task.value = task.value / 2;
|
||||
}
|
||||
if (task.group && task.group.approval && task.group.approval.approved) {
|
||||
task.group.approval.approved = false;
|
||||
task.group.approval.dateApproved = null;
|
||||
task.group.approval.requested = false;
|
||||
task.group.approval.requestedDate = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Finished tallying
|
||||
|
|
|
|||
|
|
@ -105,8 +105,19 @@ async function cronAsync (req, res) {
|
|||
|
||||
// Save user and tasks
|
||||
let toSave = [user.save()];
|
||||
tasks.forEach(task => {
|
||||
tasks.forEach(async task => {
|
||||
if (task.isModified()) toSave.push(task.save());
|
||||
if (task.isModified() && task.group && task.group.taskId) {
|
||||
const groupTask = await Tasks.Task.findOne({
|
||||
_id: task.group.taskId,
|
||||
}).exec();
|
||||
|
||||
if (groupTask) {
|
||||
let delta = Math.pow(0.9747, task.value) * -1;
|
||||
if (groupTask.group.assignedUsers) delta /= groupTask.group.assignedUsers.length;
|
||||
await groupTask.scoreChallengeTask(delta, 'down');
|
||||
}
|
||||
}
|
||||
});
|
||||
await Promise.all(toSave);
|
||||
|
||||
|
|
|
|||
|
|
@ -200,8 +200,8 @@ TaskSchema.methods.scoreChallengeTask = async function scoreChallengeTask (delta
|
|||
if (chalTask.type === 'habit' || chalTask.type === 'daily') {
|
||||
// Add only one history entry per day
|
||||
const history = chalTask.history;
|
||||
const lastChallengHistoryIndex = history.length - 1;
|
||||
const lastHistoryEntry = history[lastChallengHistoryIndex];
|
||||
const lastChallengeHistoryIndex = history.length - 1;
|
||||
const lastHistoryEntry = history[lastChallengeHistoryIndex];
|
||||
|
||||
if (
|
||||
lastHistoryEntry && lastHistoryEntry.date &&
|
||||
|
|
@ -222,7 +222,7 @@ TaskSchema.methods.scoreChallengeTask = async function scoreChallengeTask (delta
|
|||
}
|
||||
}
|
||||
|
||||
chalTask.markModified(`history.${lastChallengHistoryIndex}`);
|
||||
chalTask.markModified(`history.${lastChallengeHistoryIndex}`);
|
||||
} else {
|
||||
const historyEntry = {
|
||||
date: Number(new Date()),
|
||||
|
|
|
|||
Loading…
Reference in a new issue