mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Merge branch 'develop' into party-chat-translations
This commit is contained in:
@@ -101,21 +101,25 @@ api.registerLocal = {
|
||||
let existingUser = res.locals.user; // If adding local auth to social user
|
||||
|
||||
req.checkBody({
|
||||
email: {
|
||||
notEmpty: {errorMessage: res.t('missingEmail')},
|
||||
isEmail: {errorMessage: res.t('notAnEmail')},
|
||||
},
|
||||
username: {
|
||||
notEmpty: {errorMessage: res.t('missingUsername')},
|
||||
isLength: {options: {min: USERNAME_LENGTH_MIN, max: USERNAME_LENGTH_MAX}, errorMessage: res.t('usernameWrongLength')},
|
||||
notEmpty: true,
|
||||
errorMessage: res.t('missingUsername'),
|
||||
// TODO use the constants in the error message above
|
||||
isLength: {options: {min: USERNAME_LENGTH_MIN, max: USERNAME_LENGTH_MAX}, errorMessage: res.t('usernameWrongLength')},
|
||||
matches: {options: /^[-_a-zA-Z0-9]+$/, errorMessage: res.t('usernameBadCharacters')},
|
||||
},
|
||||
email: {
|
||||
notEmpty: true,
|
||||
errorMessage: res.t('missingEmail'),
|
||||
isEmail: {errorMessage: res.t('notAnEmail')},
|
||||
},
|
||||
password: {
|
||||
notEmpty: {errorMessage: res.t('missingPassword')},
|
||||
notEmpty: true,
|
||||
errorMessage: res.t('missingPassword'),
|
||||
equals: {options: [req.body.confirmPassword], errorMessage: res.t('passwordConfirmationMatch')},
|
||||
},
|
||||
});
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
@@ -476,7 +480,7 @@ api.updateUsername = {
|
||||
notEmpty: {errorMessage: res.t('missingPassword')},
|
||||
},
|
||||
username: {
|
||||
notEmpty: { errorMessage: res.t('missingUsername') },
|
||||
notEmpty: {errorMessage: res.t('missingUsername')},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -449,7 +449,7 @@ api.getGroupChallenges = {
|
||||
method: 'GET',
|
||||
url: '/challenges/groups/:groupId',
|
||||
middlewares: [authWithHeaders({
|
||||
userFieldsToExclude: ['inbox'],
|
||||
userFieldsToInclude: ['_id', 'party', 'guilds'],
|
||||
})],
|
||||
async handler (req, res) {
|
||||
let user = res.locals.user;
|
||||
@@ -463,10 +463,10 @@ api.getGroupChallenges = {
|
||||
if (groupId === 'party') groupId = user.party._id;
|
||||
if (groupId === 'habitrpg') groupId = TAVERN_ID;
|
||||
|
||||
let group = await Group.getGroup({user, groupId});
|
||||
const group = await Group.getGroup({ user, groupId });
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
let challenges = await Challenge.find({group: groupId})
|
||||
const challenges = await Challenge.find({ group: groupId })
|
||||
.sort('-createdAt')
|
||||
// .populate('leader', nameFields) // Only populate the leader as the group is implicit
|
||||
.exec();
|
||||
|
||||
@@ -196,7 +196,6 @@ api.createGroupPlan = {
|
||||
|
||||
// @TODO: Change message
|
||||
if (group.privacy !== 'private') throw new NotAuthorized(res.t('partyMustbePrivate'));
|
||||
group.memberCount = await User.count({ $or: [{ 'party._id': group._id }, { guilds: group._id }] }).exec();
|
||||
group.leader = user._id;
|
||||
user.guilds.push(group._id);
|
||||
|
||||
@@ -385,7 +384,7 @@ api.getGroup = {
|
||||
method: 'GET',
|
||||
url: '/groups/:groupId',
|
||||
middlewares: [authWithHeaders({
|
||||
userFieldsToExclude: ['inbox'],
|
||||
userFieldsToInclude: ['_id', 'party', 'guilds', 'contributor'],
|
||||
})],
|
||||
async handler (req, res) {
|
||||
let user = res.locals.user;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
|
||||
let api = {};
|
||||
|
||||
// @TODO export this const, cannot export it from here because only routes are exported from controllers
|
||||
const LAST_ANNOUNCEMENT_TITLE = 'SPLASHY SKINS';
|
||||
const LAST_ANNOUNCEMENT_TITLE = 'HABITICA COMIC-CON MEETUP AND WIKI SPOTLIGHT ON THE POMODORO TECHNIQUE';
|
||||
const worldDmg = { // @TODO
|
||||
bailey: false,
|
||||
};
|
||||
@@ -30,14 +30,26 @@ api.getNews = {
|
||||
<div class="mr-3 ${baileyClass}"></div>
|
||||
<div class="media-body">
|
||||
<h1 class="align-self-center">${res.t('newStuff')}</h1>
|
||||
<h2>7/10/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
<h2>7/19/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||
</div>
|
||||
<div class="promo_splashy_skins"></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<p>The Seasonal Edition Splashy Skins are available until July 31st! You can complete your summer avatar look with Clownfish, Deep Ocean, Tropical Water, Mergold, Mergreen, Merblue, Merruby, and Shark Skins.</p>
|
||||
<p>This Seasonal Edition customization set will only be available to purchase until July 31st, after which they'll be gone until next year, so be sure to swoop them up now! You can find them in User > Edit Avatar!</p>
|
||||
<div class="small mb-3">by Lemoness and UncommonCriminal</div>
|
||||
<div class="media align-items-center">
|
||||
<div class="media-body">
|
||||
<h3>Habitica at San Diego Comic Con!</h3>
|
||||
<p>Beffymaroo will be representing Habitica at San Diego Comic Con this year. If you’d like to meet her, along with other fellow Habiticans, join us at the Habitica SDCC Meetup! Beffymaroo will be handing out Habitica stickers, promo codes for the Unconventional Armor set, and other exciting special swag (quantities limited!).</p>
|
||||
<p>You can find the meetup on Saturday, July 21, at the San Diego Bayfront Hilton lobby from 12:00-1:00 PM! Look for the purple Gryphon banner. Can’t wait to meet you :)</p>
|
||||
</div>
|
||||
<div class="promo_unconventional_armor ml-3 mb-3"></div>
|
||||
</div>
|
||||
<div class="media align-items-center">
|
||||
<div class="scene_pomodoro mr-3"></div>
|
||||
<div class="media-body">
|
||||
<h3>Wiki Spotlight: The Pomodoro Technique</h3>
|
||||
<p>This month's <a href='https://habitica.wordpress.com/2018/07/18/pomodoro/' target='_blank'>featured Wiki article</a> is about the Pomodoro Technique! We hope that it will help you as you look for new productivity strategies. Be sure to check it out, and let us know what you think by reaching out on <a href='https://twitter.com/habitica' target='_blank'>Twitter</a>, <a href='http://blog.habitrpg.com' target='_blank'>Tumblr</a>, and <a href='https://facebook.com/habitica' target='_blank'>Facebook</a>.</p>
|
||||
<div class="small mb-3">by shanaqui and the Wiki Wizards</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from '../../libs/webhook';
|
||||
import { removeFromArray } from '../../libs/collectionManipulators';
|
||||
import * as Tasks from '../../models/task';
|
||||
import { handleSharedCompletion } from '../../libs/groupTasks';
|
||||
import { model as Challenge } from '../../models/challenge';
|
||||
import { model as Group } from '../../models/group';
|
||||
import { model as User } from '../../models/user';
|
||||
@@ -287,7 +288,7 @@ api.getUserTasks = {
|
||||
method: 'GET',
|
||||
url: '/tasks/user',
|
||||
middlewares: [authWithHeaders({
|
||||
userFieldsToExclude: ['inbox'],
|
||||
userFieldsToInclude: ['_id', 'tasksOrder', 'preferences'],
|
||||
})],
|
||||
async handler (req, res) {
|
||||
let types = Tasks.tasksTypes.map(type => `${type}s`);
|
||||
@@ -297,10 +298,10 @@ api.getUserTasks = {
|
||||
let validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
let user = res.locals.user;
|
||||
let dueDate = req.query.dueDate;
|
||||
const user = res.locals.user;
|
||||
const dueDate = req.query.dueDate;
|
||||
|
||||
let tasks = await getTasks(req, res, {user, dueDate});
|
||||
const tasks = await getTasks(req, res, { user, dueDate });
|
||||
return res.respond(200, tasks);
|
||||
},
|
||||
};
|
||||
@@ -490,6 +491,9 @@ api.updateTask = {
|
||||
if (sanitizedObj.requiresApproval) {
|
||||
task.group.approval.required = true;
|
||||
}
|
||||
if (sanitizedObj.sharedCompletion) {
|
||||
task.group.sharedCompletion = sanitizedObj.sharedCompletion;
|
||||
}
|
||||
|
||||
setNextDue(task, user);
|
||||
let savedTask = await task.save();
|
||||
@@ -653,6 +657,12 @@ api.scoreTask = {
|
||||
user.save(),
|
||||
task.save(),
|
||||
];
|
||||
|
||||
if (task.group && task.group.taskId) {
|
||||
await handleSharedCompletion(task);
|
||||
}
|
||||
|
||||
// Save results and handle request
|
||||
if (taskOrderPromise) promises.push(taskOrderPromise);
|
||||
let results = await Promise.all(promises);
|
||||
|
||||
|
||||
@@ -12,10 +12,13 @@ import {
|
||||
getTasks,
|
||||
moveTask,
|
||||
} from '../../../libs/taskManager';
|
||||
import { handleSharedCompletion } from '../../../libs/groupTasks';
|
||||
import apiError from '../../../libs/apiError';
|
||||
|
||||
let requiredGroupFields = '_id leader tasksOrder name';
|
||||
// @TODO: abstract to task lib
|
||||
let types = Tasks.tasksTypes.map(type => `${type}s`);
|
||||
types.push('completedTodos', '_allCompletedTodos'); // _allCompletedTodos is currently in BETA and is likely to be removed in future
|
||||
|
||||
function canNotEditTasks (group, user, assignedUserId) {
|
||||
let isNotGroupLeader = group.leader !== user._id;
|
||||
@@ -345,7 +348,7 @@ api.approveTask = {
|
||||
}
|
||||
|
||||
// Remove old notifications
|
||||
let managerPromises = [];
|
||||
let approvalPromises = [];
|
||||
managers.forEach((manager) => {
|
||||
let notificationIndex = manager.notifications.findIndex(function findNotification (notification) {
|
||||
return notification && notification.data && notification.data.taskId === task._id && notification.type === 'GROUP_TASK_APPROVAL';
|
||||
@@ -353,7 +356,7 @@ api.approveTask = {
|
||||
|
||||
if (notificationIndex !== -1) {
|
||||
manager.notifications.splice(notificationIndex, 1);
|
||||
managerPromises.push(manager.save());
|
||||
approvalPromises.push(manager.save());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -369,9 +372,11 @@ api.approveTask = {
|
||||
direction,
|
||||
});
|
||||
|
||||
managerPromises.push(task.save());
|
||||
managerPromises.push(assignedUser.save());
|
||||
await Promise.all(managerPromises);
|
||||
await handleSharedCompletion(task);
|
||||
|
||||
approvalPromises.push(task.save());
|
||||
approvalPromises.push(assignedUser.save());
|
||||
await Promise.all(approvalPromises);
|
||||
|
||||
res.respond(200, task);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user