Merge branch 'develop' into sabrecat/teams-rebase

This commit is contained in:
SabreCat
2022-08-01 15:40:08 -05:00
14 changed files with 205 additions and 13 deletions

View File

@@ -4,6 +4,7 @@ import {
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
import { MAX_SUMMARY_SIZE_FOR_CHALLENGES } from '../../../../../website/common/script/constants';
describe('POST /challenges', () => { describe('POST /challenges', () => {
it('returns error when group is empty', async () => { it('returns error when group is empty', async () => {
@@ -60,6 +61,22 @@ describe('POST /challenges', () => {
}); });
}); });
it('return error when creating a challenge with summary with greater than MAX_SUMMARY_SIZE_FOR_CHALLENGES characters', async () => {
const user = await generateUser();
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_CHALLENGES + 1);
const group = createAndPopulateGroup({
members: 1,
});
await expect(user.post('/challenges', {
group: group._id,
summary,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
context('Creating a challenge for a valid group', () => { context('Creating a challenge for a valid group', () => {
let groupLeader; let groupLeader;
let group; let group;

View File

@@ -4,6 +4,7 @@ import {
createAndPopulateGroup, createAndPopulateGroup,
translate as t, translate as t,
} from '../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
import { MAX_SUMMARY_SIZE_FOR_CHALLENGES } from '../../../../../website/common/script/constants';
describe('PUT /challenges/:challengeId', () => { describe('PUT /challenges/:challengeId', () => {
let privateGuild; let user; let nonMember; let challenge; let let privateGuild; let user; let nonMember; let challenge; let
@@ -91,4 +92,15 @@ describe('PUT /challenges/:challengeId', () => {
expect(res.name).to.equal('New Challenge Name'); expect(res.name).to.equal('New Challenge Name');
expect(res.description).to.equal('New challenge description.'); expect(res.description).to.equal('New challenge description.');
}); });
it('return error when challenge summary is greater than MAX_SUMMARY_SIZE_FOR_CHALLENGES characters', async () => {
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_CHALLENGES + 1);
await expect(user.put(`/challenges/${challenge._id}`, {
summary,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
}); });

View File

@@ -3,6 +3,7 @@ import {
translate as t, translate as t,
} from '../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
import { model as Group } from '../../../../../website/server/models/group'; import { model as Group } from '../../../../../website/server/models/group';
import { MAX_SUMMARY_SIZE_FOR_GUILDS } from '../../../../../website/common/script/constants';
describe('POST /group', () => { describe('POST /group', () => {
let user; let user;
@@ -71,6 +72,20 @@ describe('POST /group', () => {
expect(updatedGroup.summary).to.eql(summary); expect(updatedGroup.summary).to.eql(summary);
}); });
it('returns error when summary is longer than MAX_SUMMARY_SIZE_FOR_GUILDS characters', async () => {
const name = 'Test Group';
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_GUILDS + 1);
await expect(user.post('/groups', {
name,
type: 'guild',
summary,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
}); });
context('Guilds', () => { context('Guilds', () => {

View File

@@ -3,6 +3,7 @@ import {
generateUser, generateUser,
translate as t, translate as t,
} from '../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
import { MAX_SUMMARY_SIZE_FOR_GUILDS } from '../../../../../website/common/script/constants';
describe('PUT /group', () => { describe('PUT /group', () => {
let leader; let nonLeader; let groupToUpdate; let let leader; let nonLeader; let groupToUpdate; let
@@ -130,4 +131,15 @@ describe('PUT /group', () => {
expect(response.bannedWordsAllowed).to.eql(undefined); expect(response.bannedWordsAllowed).to.eql(undefined);
}); });
it('returns error when summary is longer than MAX_SUMMARY_SIZE_FOR_GUILDS characters', async () => {
const summary = 'A'.repeat(MAX_SUMMARY_SIZE_FOR_GUILDS + 1);
await expect(leader.put(`/groups/${groupToUpdate._id}`, {
summary,
})).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
}); });

View File

@@ -690,6 +690,11 @@
width: 141px; width: 141px;
height: 147px; height: 147px;
} }
.background_by_a_campfire {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_by_a_campfire.png');
width: 141px;
height: 147px;
}
.background_camping_out { .background_camping_out {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_camping_out.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_camping_out.png');
width: 141px; width: 141px;
@@ -1354,6 +1359,11 @@
width: 141px; width: 141px;
height: 147px; height: 147px;
} }
.background_messy_room {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_messy_room.png');
width: 141px;
height: 147px;
}
.background_meteor_shower { .background_meteor_shower {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_meteor_shower.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_meteor_shower.png');
width: 141px; width: 141px;
@@ -1509,6 +1519,11 @@
width: 141px; width: 141px;
height: 147px; height: 147px;
} }
.background_rainbow_eucalyptus {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rainbow_eucalyptus.png');
width: 141px;
height: 147px;
}
.background_rainbow_meadow { .background_rainbow_meadow {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rainbow_meadow.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rainbow_meadow.png');
width: 141px; width: 141px;
@@ -2231,6 +2246,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.icon_background_by_a_campfire {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_by_a_campfire.png');
width: 68px;
height: 68px;
}
.icon_background_camping_out { .icon_background_camping_out {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_camping_out.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_camping_out.png');
width: 68px; width: 68px;
@@ -2900,6 +2920,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.icon_background_messy_room {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_messy_room.png');
width: 68px;
height: 68px;
}
.icon_background_meteor_shower { .icon_background_meteor_shower {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_meteor_shower.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_meteor_shower.png');
width: 68px; width: 68px;
@@ -3055,6 +3080,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.icon_background_rainbow_eucalyptus {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_rainbow_eucalyptus.png');
width: 68px;
height: 68px;
}
.icon_background_rainbow_meadow { .icon_background_rainbow_meadow {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_rainbow_meadow.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_rainbow_meadow.png');
width: 68px; width: 68px;
@@ -18970,6 +19000,11 @@
width: 90px; width: 90px;
height: 90px; height: 90px;
} }
.shield_armoire_dustpan {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_dustpan.png');
width: 114px;
height: 90px;
}
.shield_armoire_fancyBlownGlassVase { .shield_armoire_fancyBlownGlassVase {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_fancyBlownGlassVase.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_fancyBlownGlassVase.png');
width: 114px; width: 114px;
@@ -20180,6 +20215,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_shield_armoire_dustpan {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_dustpan.png');
width: 68px;
height: 68px;
}
.shop_shield_armoire_fancyBlownGlassVase { .shop_shield_armoire_fancyBlownGlassVase {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_fancyBlownGlassVase.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_fancyBlownGlassVase.png');
width: 68px; width: 68px;
@@ -20565,6 +20605,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_weapon_armoire_featherDuster {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_featherDuster.png');
width: 68px;
height: 68px;
}
.shop_weapon_armoire_festivalFirecracker { .shop_weapon_armoire_festivalFirecracker {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_festivalFirecracker.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_festivalFirecracker.png');
width: 68px; width: 68px;
@@ -20805,6 +20850,11 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_weapon_armoire_pushBroom {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_pushBroom.png');
width: 68px;
height: 68px;
}
.shop_weapon_armoire_rancherLasso { .shop_weapon_armoire_rancherLasso {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_rancherLasso.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_rancherLasso.png');
width: 68px; width: 68px;
@@ -21430,6 +21480,11 @@
width: 114px; width: 114px;
height: 90px; height: 90px;
} }
.weapon_armoire_featherDuster {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_featherDuster.png');
width: 114px;
height: 90px;
}
.weapon_armoire_festivalFirecracker { .weapon_armoire_festivalFirecracker {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_festivalFirecracker.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_festivalFirecracker.png');
width: 90px; width: 90px;
@@ -21670,6 +21725,11 @@
width: 114px; width: 114px;
height: 90px; height: 90px;
} }
.weapon_armoire_pushBroom {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_pushBroom.png');
width: 114px;
height: 90px;
}
.weapon_armoire_rancherLasso { .weapon_armoire_rancherLasso {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_rancherLasso.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_rancherLasso.png');
width: 90px; width: 90px;
@@ -26925,6 +26985,31 @@
width: 117px; width: 117px;
height: 120px; height: 120px;
} }
.eyewear_mystery_202208 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_mystery_202208.png');
width: 114px;
height: 90px;
}
.head_mystery_202208 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202208.png');
width: 114px;
height: 90px;
}
.shop_eyewear_mystery_202208 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_eyewear_mystery_202208.png');
width: 68px;
height: 68px;
}
.shop_head_mystery_202208 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_mystery_202208.png');
width: 68px;
height: 68px;
}
.shop_set_mystery_202208 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202208.png');
width: 68px;
height: 68px;
}
.broad_armor_mystery_301404 { .broad_armor_mystery_301404 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png'); background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
width: 90px; width: 90px;

View File

@@ -803,6 +803,14 @@
"backgroundUnderwaterStatuesText": "Underwater Statue Garden", "backgroundUnderwaterStatuesText": "Underwater Statue Garden",
"backgroundUnderwaterStatuesNotes": "Try not to blink in an Underwater Statue Garden.", "backgroundUnderwaterStatuesNotes": "Try not to blink in an Underwater Statue Garden.",
"backgrounds082022": "SET 99: Released August 2022",
"backgroundRainbowEucalyptusText": "Rainbow Eucalyptus",
"backgroundRainbowEucalyptusNotes": "Admire a Rainbow Eucalyptus grove.",
"backgroundMessyRoomText": "Messy Room",
"backgroundMessyRoomNotes": "Tidy up a Messy Room.",
"backgroundByACampfireText": "By A Campfire",
"backgroundByACampfireNotes": "Bask in the glow By a Campfire.",
"timeTravelBackgrounds": "Steampunk Backgrounds", "timeTravelBackgrounds": "Steampunk Backgrounds",
"backgroundAirshipText": "Airship", "backgroundAirshipText": "Airship",
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.", "backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",

View File

@@ -650,6 +650,10 @@
"weaponArmoirePinkKiteNotes": "Diving, twirling, soaring high, your kite stands out against the sky. Increases all stats by <%= attrs %> each. Enchanted Armoire: Kite Set (Item 4 of 5)", "weaponArmoirePinkKiteNotes": "Diving, twirling, soaring high, your kite stands out against the sky. Increases all stats by <%= attrs %> each. Enchanted Armoire: Kite Set (Item 4 of 5)",
"weaponArmoireYellowKiteText": "Yellow Kite", "weaponArmoireYellowKiteText": "Yellow Kite",
"weaponArmoireYellowKiteNotes": "Swooping and swerving to and fro, watch your cheerful kite go. Increases all stats by <%= attrs %> each. Enchanted Armoire: Kite Set (Item 5 of 5)", "weaponArmoireYellowKiteNotes": "Swooping and swerving to and fro, watch your cheerful kite go. Increases all stats by <%= attrs %> each. Enchanted Armoire: Kite Set (Item 5 of 5)",
"weaponArmoirePushBroomText": "Push Broom",
"weaponArmoirePushBroomNotes": "Take this tidying tool on your adventures and always be able to sweep a sooty stoop or clear cobwebs from corners. Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Cleaning Supplies Set (Item 1 of 3)",
"weaponArmoireFeatherDusterText": "Feather Duster",
"weaponArmoireFeatherDusterNotes": "Let these fancy feathers fly over all your old objects to make them shine like new. Just beware of the disturbed dust so you dont sneeze! Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Cleaning Supplies Set (Item 2 of 3)",
"armor": "armor", "armor": "armor",
"armorCapitalized": "Armor", "armorCapitalized": "Armor",
@@ -2487,6 +2491,8 @@
"shieldArmoireSnareDrumNotes": "Rat-a-tat-tat! Gather your party for a parade or march into battle by playing this drum. Increases Constitution by <%= con %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 3 of 3)", "shieldArmoireSnareDrumNotes": "Rat-a-tat-tat! Gather your party for a parade or march into battle by playing this drum. Increases Constitution by <%= con %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 3 of 3)",
"shieldArmoireTreasureMapText": "Treasure Map", "shieldArmoireTreasureMapText": "Treasure Map",
"shieldArmoireTreasureMapNotes": "X marks the spot! You never know what youll find when you follow this handy map to fabled treasures: gold, jewels, relics, or perhaps a petrified orange? Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 3 of 3).", "shieldArmoireTreasureMapNotes": "X marks the spot! You never know what youll find when you follow this handy map to fabled treasures: gold, jewels, relics, or perhaps a petrified orange? Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 3 of 3).",
"shieldArmoireDustpanText": "Dustpan",
"shieldArmoireDustpanNotes": "Have this handy handheld dustpan ready every time you clean. A vanishing spell cast on it means you never have to search for a trash can to empty it into. Increases Intelligence and Constitution by <%= attrs %> each. Enchanted Armoire: Cleaning Supplies Set (Item 3 of 3).",
"back": "Back Accessory", "back": "Back Accessory",
"backBase0Text": "No Back Accessory", "backBase0Text": "No Back Accessory",

View File

@@ -510,6 +510,11 @@ const backgrounds = {
underwater_cave: { }, underwater_cave: { },
underwater_statues: { }, underwater_statues: { },
}, },
backgrounds082022: {
rainbow_eucalyptus: { },
messy_room: { },
by_a_campfire: { },
},
timeTravelBackgrounds: { timeTravelBackgrounds: {
airship: { airship: {
price: 1, price: 1,

View File

@@ -1100,6 +1100,11 @@ const shield = {
str: 4, str: 4,
set: 'fancyPirate', set: 'fancyPirate',
}, },
dustpan: {
int: 4,
con: 4,
set: 'cleaningSupplies',
},
}; };
const headAccessory = { const headAccessory = {
@@ -1524,6 +1529,16 @@ const weapon = {
per: 3, per: 3,
set: 'kite', set: 'kite',
}, },
pushBroom: {
str: 4,
int: 4,
set: 'cleaningSupplies',
},
featherDuster: {
con: 4,
per: 4,
set: 'cleaningSupplies',
},
}; };
forEach({ forEach({

View File

@@ -39,4 +39,5 @@ export default {
directionUpDown: '"direction" is required and must be "up" or "down".', directionUpDown: '"direction" is required and must be "up" or "down".',
invalidTaskIdentifier: 'A task is identified by its UUID or alias.', invalidTaskIdentifier: 'A task is identified by its UUID or alias.',
invalidTaskScorings: 'This API route expects a body in the form of [{id, direction}].', invalidTaskScorings: 'This API route expects a body in the form of [{id, direction}].',
summaryLengthExceedsMax: 'Summary length is too high.',
}; };

View File

@@ -30,6 +30,10 @@ import {
} from '../../libs/challenges'; } from '../../libs/challenges';
import apiError from '../../libs/apiError'; import apiError from '../../libs/apiError';
import common from '../../../common';
const { MAX_SUMMARY_SIZE_FOR_CHALLENGES } = common.constants;
const api = {}; const api = {};
/** /**
@@ -200,6 +204,7 @@ api.createChallenge = {
const { user } = res.locals; const { user } = res.locals;
req.checkBody('group', apiError('groupIdRequired')).notEmpty(); req.checkBody('group', apiError('groupIdRequired')).notEmpty();
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES });
const validationErrors = req.validationErrors(); const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;
@@ -707,6 +712,7 @@ api.updateChallenge = {
middlewares: [authWithHeaders()], middlewares: [authWithHeaders()],
async handler (req, res) { async handler (req, res) {
req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID();
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES });
const validationErrors = req.validationErrors(); const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;

View File

@@ -28,6 +28,7 @@ import amzLib from '../../libs/payments/amazon';
import apiError from '../../libs/apiError'; import apiError from '../../libs/apiError';
import { model as UserNotification } from '../../models/userNotification'; import { model as UserNotification } from '../../models/userNotification';
const { MAX_SUMMARY_SIZE_FOR_GUILDS } = common.constants;
const MAX_EMAIL_INVITES_BY_USER = 200; const MAX_EMAIL_INVITES_BY_USER = 200;
const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL'); const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL');
@@ -118,6 +119,11 @@ api.createGroup = {
const group = new Group(Group.sanitize(req.body)); const group = new Group(Group.sanitize(req.body));
group.leader = user._id; group.leader = user._id;
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS });
const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
if (group.type === 'guild') { if (group.type === 'guild') {
if (group.privacy === 'public' && user.flags.chatRevoked) throw new NotAuthorized(res.t('chatPrivilegesRevoked')); if (group.privacy === 'public' && user.flags.chatRevoked) throw new NotAuthorized(res.t('chatPrivilegesRevoked'));
if (user.balance < 1) throw new NotAuthorized(res.t('messageInsufficientGems')); if (user.balance < 1) throw new NotAuthorized(res.t('messageInsufficientGems'));
@@ -191,7 +197,7 @@ api.createGroupPlan = {
const group = new Group(Group.sanitize(req.body.groupToCreate)); const group = new Group(Group.sanitize(req.body.groupToCreate));
req.checkBody('paymentType', res.t('paymentTypeRequired')).notEmpty(); req.checkBody('paymentType', res.t('paymentTypeRequired')).notEmpty();
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS });
const validationErrors = req.validationErrors(); const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;
@@ -464,6 +470,7 @@ api.updateGroup = {
const { user } = res.locals; const { user } = res.locals;
req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); req.checkParams('groupId', apiError('groupIdRequired')).notEmpty();
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS });
const validationErrors = req.validationErrors(); const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors; if (validationErrors) throw validationErrors;

View File

@@ -714,8 +714,11 @@ api.transferGems = {
throw new NotAuthorized(res.t('badAmountOfGemsToSend')); throw new NotAuthorized(res.t('badAmountOfGemsToSend'));
} }
// Received from {sender}
await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.auth.local.username); await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.auth.local.username);
await sender.updateBalance(-amount, 'gift_send', sender._id, receiver.auth.local.username);
// Gifted to {receiver}
await sender.updateBalance(-amount, 'gift_send', receiver._id, receiver.auth.local.username);
// @TODO necessary? Also saved when sending the inbox message // @TODO necessary? Also saved when sending the inbox message
const promises = [receiver.save(), sender.save()]; const promises = [receiver.save(), sender.save()];
await Promise.all(promises); await Promise.all(promises);