mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 05:37:22 +01:00
WIP(teams): draft of server literal-actual-cron script
This commit is contained in:
80
scripts/team-cron.js
Normal file
80
scripts/team-cron.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import forEach from 'lodash/forEach';
|
||||
import { model as Group } from '../website/server/models/group';
|
||||
import { model as User } from '../website/server/models/user';
|
||||
import * as Tasks from '../website/server/models/task';
|
||||
import { daysSince, shouldDo } from '../website/common/script/cron';
|
||||
|
||||
const TASK_VALUE_CHANGE_FACTOR = 0.9747;
|
||||
const MIN_TASK_VALUE = -47.27;
|
||||
|
||||
async function updateTeamTasks (team) {
|
||||
const toSave = [];
|
||||
const teamLeader = await User.findOne({ _id: team.leader }, 'preferences').exec();
|
||||
|
||||
if (
|
||||
!team.cron || !team.cron.lastProcessed
|
||||
|| daysSince(team.cron.lastProcessed, teamLeader.preferences) > 0
|
||||
) {
|
||||
const tasks = await Tasks.Task.find({
|
||||
'group.id': team._id,
|
||||
'group.assignedUsers': [],
|
||||
userId: { $exists: false },
|
||||
$or: [
|
||||
{ type: 'todo', completed: false },
|
||||
{ type: { $in: ['habit', 'daily'] } },
|
||||
],
|
||||
}).exec();
|
||||
|
||||
const tasksByType = {
|
||||
habits: [], dailys: [], todos: [], rewards: [],
|
||||
};
|
||||
forEach(tasks, task => tasksByType[`${task.type}s`].push(task));
|
||||
|
||||
forEach(tasksByType.habits, habit => {
|
||||
if (!(habit.up && habit.down) && habit.value !== 0) {
|
||||
habit.value *= 0.5;
|
||||
if (Math.abs(habit.value) < 0.1) habit.value = 0;
|
||||
toSave.push(habit.save());
|
||||
}
|
||||
});
|
||||
forEach(tasksByType.todos, todo => {
|
||||
if (!todo.completed) {
|
||||
const delta = TASK_VALUE_CHANGE_FACTOR ** todo.value;
|
||||
todo.value -= delta;
|
||||
if (todo.value < MIN_TASK_VALUE) todo.value = MIN_TASK_VALUE;
|
||||
toSave.push(todo.save());
|
||||
}
|
||||
});
|
||||
forEach(tasksByType.dailys, daily => {
|
||||
if (daily.completed) {
|
||||
daily.completed = false;
|
||||
} else if (shouldDo(team.cron.lastProcessed, daily, teamLeader.preferences)) {
|
||||
const delta = TASK_VALUE_CHANGE_FACTOR ** daily.value;
|
||||
daily.value -= delta;
|
||||
if (daily.value < MIN_TASK_VALUE) daily.value = MIN_TASK_VALUE;
|
||||
}
|
||||
daily.isDue = shouldDo(new Date(), daily, teamLeader.preferences);
|
||||
if (daily.isModified()) toSave.push(daily.save());
|
||||
});
|
||||
|
||||
if (!team.cron) team.cron = {};
|
||||
team.cron.lastProcessed = new Date();
|
||||
toSave.push(team.save());
|
||||
}
|
||||
|
||||
return Promise.all(toSave);
|
||||
}
|
||||
|
||||
export default async function processTeamsCron () {
|
||||
const activeTeams = await Group.find({
|
||||
'purchased.plan.customerId': { $exists: true },
|
||||
$or: [
|
||||
{ 'purchased.plan.dateTerminated': { $exists: false } },
|
||||
{ 'purchased.plan.dateTerminated': null },
|
||||
{ 'purchased.plan.dateTerminated': { $gt: new Date() } },
|
||||
],
|
||||
}).exec();
|
||||
|
||||
const cronPromises = activeTeams.map(updateTeamTasks);
|
||||
return Promise.all(cronPromises);
|
||||
}
|
||||
@@ -73,37 +73,13 @@ async function cronAsync (req, res) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const teamsLed = await user.teamsLed();
|
||||
let tasksQuery;
|
||||
|
||||
if (teamsLed.length > 0) {
|
||||
tasksQuery = {
|
||||
$and: [
|
||||
{
|
||||
$or: [
|
||||
{ userId: user._id },
|
||||
{ userId: { $exists: false }, 'group.id': { $in: teamsLed }, 'group.assignedUsers': { $size: 0 } },
|
||||
],
|
||||
},
|
||||
{
|
||||
$or: [
|
||||
{ type: 'todo', completed: false },
|
||||
{ type: { $in: ['habit', 'daily'] } },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
tasksQuery = {
|
||||
userId: user._id,
|
||||
$or: [
|
||||
{ type: 'todo', completed: false },
|
||||
{ type: { $in: ['habit', 'daily'] } },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const tasks = await Tasks.Task.find(tasksQuery).exec();
|
||||
const tasks = await Tasks.Task.find({
|
||||
userId: user._id,
|
||||
$or: [ // Exclude completed todos
|
||||
{ type: 'todo', completed: false },
|
||||
{ type: { $in: ['habit', 'daily', 'reward'] } },
|
||||
],
|
||||
}).exec();
|
||||
|
||||
const tasksByType = {
|
||||
habits: [], dailys: [], todos: [], rewards: [],
|
||||
@@ -141,36 +117,20 @@ async function cronAsync (req, res) {
|
||||
|
||||
// Save user and tasks
|
||||
const toSave = [user.save()];
|
||||
const groupTasks = [];
|
||||
const groupTasksByType = {
|
||||
habits: [], dailys: [], todos: [], rewards: [],
|
||||
};
|
||||
for (const task of tasks) {
|
||||
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({ // eslint-disable-line no-await-in-loop
|
||||
const groupTask = await Tasks.Task.findOne({
|
||||
_id: task.group.taskId,
|
||||
}).exec();
|
||||
|
||||
if (groupTask) {
|
||||
groupTasks.push(groupTask);
|
||||
groupTasksByType[`${groupTask.type}s`].push(groupTask);
|
||||
let delta = (0.9747 ** task.value) * -1;
|
||||
if (groupTask.group.assignedUsers) delta /= groupTask.group.assignedUsers.length;
|
||||
await groupTask.scoreChallengeTask(delta, 'down');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (groupTasks.length > 0) {
|
||||
await cron({
|
||||
user,
|
||||
tasksByType: groupTasksByType,
|
||||
now,
|
||||
daysMissed,
|
||||
analytics,
|
||||
timezoneUtcOffsetFromUserPrefs,
|
||||
headers: req.headers,
|
||||
});
|
||||
groupTasks.forEach(async cronnedGroupTask => {
|
||||
if (cronnedGroupTask.isModified()) toSave.push(cronnedGroupTask.save());
|
||||
});
|
||||
}
|
||||
});
|
||||
await Promise.all(toSave);
|
||||
|
||||
await Group.processQuestProgress(user, progress);
|
||||
|
||||
@@ -144,6 +144,9 @@ export const schema = new Schema({
|
||||
slug: { $type: String },
|
||||
name: { $type: String },
|
||||
}],
|
||||
cron: {
|
||||
lastProcessed: { $type: Date },
|
||||
},
|
||||
}, {
|
||||
strict: true,
|
||||
minimize: false, // So empty objects are returned
|
||||
|
||||
Reference in New Issue
Block a user