mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-13 15:38:59 +00:00
* transferGems: use receiver language translation for PM strings #7722 * chore(test): DRY up transfer gems test * chore(test): Allow check for language in translation assertion * chore(test): Add test that member locales are used in transfer gems msg * sendMessage: optionally take also the message in sender's language when present, it is stored in the sender's inbox instead of the version in the target language. * transferGems: prepare pm in both languages #7722 * sendMessage: take an object for the second parameter instead * payments: made two more gift strings translatable * buyGems: send both translations for gifted gems * buyGems: send push notifications in target user's locale * createSubscription: send both translations for gifted subs * createSubscription: send push notifications in target user's locale * transferGems: send push notifications in target user's locale * tests: adjust payment tests for translation changes * added function doc for sendMessage * tests: added bilingual test for buyGems
This commit is contained in:
parent
3f6a13d209
commit
f1a3bd5001
7 changed files with 165 additions and 47 deletions
|
|
@ -4,6 +4,14 @@ import {
|
|||
} from '../../../../helpers/api-v3-integration.helper';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
function findMessage (messages, receiverId) {
|
||||
let message = _.find(messages, (inboxMessage) => {
|
||||
return inboxMessage.uuid === receiverId;
|
||||
});
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
describe('POST /members/transfer-gems', () => {
|
||||
let userToSendMessage;
|
||||
let receiver;
|
||||
|
|
@ -116,13 +124,8 @@ describe('POST /members/transfer-gems', () => {
|
|||
let updatedReceiver = await receiver.get('/user');
|
||||
let updatedSender = await userToSendMessage.get('/user');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(updatedReceiver.inbox.messages, (inboxMessage) => {
|
||||
return inboxMessage.uuid === userToSendMessage._id;
|
||||
});
|
||||
|
||||
let sendersMessageInSendersInbox = _.find(updatedSender.inbox.messages, (inboxMessage) => {
|
||||
return inboxMessage.uuid === receiver._id;
|
||||
});
|
||||
let sendersMessageInReceiversInbox = findMessage(updatedReceiver.inbox.messages, userToSendMessage._id);
|
||||
let sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);
|
||||
|
||||
let messageSentContent = t('privateMessageGiftIntro', {
|
||||
receiverName: receiver.profile.name,
|
||||
|
|
@ -150,13 +153,8 @@ describe('POST /members/transfer-gems', () => {
|
|||
let updatedReceiver = await receiver.get('/user');
|
||||
let updatedSender = await userToSendMessage.get('/user');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(updatedReceiver.inbox.messages, (inboxMessage) => {
|
||||
return inboxMessage.uuid === userToSendMessage._id;
|
||||
});
|
||||
|
||||
let sendersMessageInSendersInbox = _.find(updatedSender.inbox.messages, (inboxMessage) => {
|
||||
return inboxMessage.uuid === receiver._id;
|
||||
});
|
||||
let sendersMessageInReceiversInbox = findMessage(updatedReceiver.inbox.messages, userToSendMessage._id);
|
||||
let sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);
|
||||
|
||||
let messageSentContent = t('privateMessageGiftIntro', {
|
||||
receiverName: receiver.profile.name,
|
||||
|
|
@ -173,4 +171,40 @@ describe('POST /members/transfer-gems', () => {
|
|||
expect(sendersMessageInSendersInbox.text).to.equal(messageSentContent);
|
||||
expect(updatedSender.balance).to.equal(0);
|
||||
});
|
||||
|
||||
it('sends transfer gems message in each participant\'s language', async () => {
|
||||
await receiver.update({
|
||||
'preferences.language': 'es',
|
||||
});
|
||||
await userToSendMessage.update({
|
||||
'preferences.language': 'cs',
|
||||
});
|
||||
await userToSendMessage.post('/members/transfer-gems', {
|
||||
gemAmount,
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let updatedReceiver = await receiver.get('/user');
|
||||
let updatedSender = await userToSendMessage.get('/user');
|
||||
|
||||
let sendersMessageInReceiversInbox = findMessage(updatedReceiver.inbox.messages, userToSendMessage._id);
|
||||
let sendersMessageInSendersInbox = findMessage(updatedSender.inbox.messages, receiver._id);
|
||||
|
||||
let [receieversMessageContent, sendersMessageContent] = ['es', 'cs'].map((lang) => {
|
||||
let messageContent = t('privateMessageGiftIntro', {
|
||||
receiverName: receiver.profile.name,
|
||||
senderName: userToSendMessage.profile.name,
|
||||
}, lang);
|
||||
messageContent += t('privateMessageGiftGemsMessage', {gemAmount}, lang);
|
||||
|
||||
return `\`${messageContent}\` `;
|
||||
});
|
||||
|
||||
expect(sendersMessageInReceiversInbox).to.exist;
|
||||
expect(sendersMessageInReceiversInbox.text).to.equal(receieversMessageContent);
|
||||
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
expect(sendersMessageInSendersInbox.text).to.equal(sendersMessageContent);
|
||||
expect(updatedSender.balance).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import notifications from '../../../../../website/server/libs/pushNotifications'
|
|||
import { model as User } from '../../../../../website/server/models/user';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
import moment from 'moment';
|
||||
import { translate as t } from '../../../../helpers/api-v3-integration.helper';
|
||||
import {
|
||||
generateGroup,
|
||||
} from '../../../../helpers/api-unit.helper.js';
|
||||
|
|
@ -181,9 +182,10 @@ describe('payments/index', () => {
|
|||
|
||||
it('sends a private message about the gift', async () => {
|
||||
await api.createSubscription(data);
|
||||
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledOnce;
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, '\`Hello recipient, sender has sent you 3 months of subscription!\`');
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg });
|
||||
});
|
||||
|
||||
it('sends an email about the gift', async () => {
|
||||
|
|
@ -697,14 +699,37 @@ describe('payments/index', () => {
|
|||
|
||||
it('sends a message from purchaser to recipient', async () => {
|
||||
await api.buyGems(data);
|
||||
let msg = '\`Hello recipient, sender has sent you 4 gems!\`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, '\`Hello recipient, sender has sent you 4 gems!\`');
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg });
|
||||
});
|
||||
|
||||
it('sends a push notification if user did not gift to self', async () => {
|
||||
await api.buyGems(data);
|
||||
expect(notifications.sendNotification).to.be.calledOnce;
|
||||
});
|
||||
|
||||
it('sends gem donation message in each participant\'s language', async () => {
|
||||
await recipient.update({
|
||||
'preferences.language': 'es',
|
||||
});
|
||||
await user.update({
|
||||
'preferences.language': 'cs',
|
||||
});
|
||||
await api.buyGems(data);
|
||||
|
||||
let [recipientsMessageContent, sendersMessageContent] = ['es', 'cs'].map((lang) => {
|
||||
let messageContent = t('giftedGemsFull', {
|
||||
username: recipient.profile.name,
|
||||
sender: user.profile.name,
|
||||
gemAmount: data.gift.gems.amount,
|
||||
}, lang);
|
||||
|
||||
return `\`${messageContent}\``;
|
||||
});
|
||||
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: recipientsMessageContent, senderMsg: sendersMessageContent });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ const STRING_DOES_NOT_EXIST_MSG = /^String '.*' not found.$/;
|
|||
// Use this to verify error messages returned by the server
|
||||
// That way, if the translated string changes, the test
|
||||
// will not break. NOTE: it checks against errors with string as well.
|
||||
export function translate (key, variables) {
|
||||
let translatedString = i18n.t(key, variables);
|
||||
export function translate (key, variables, language) {
|
||||
let translatedString = i18n.t(key, variables, language);
|
||||
|
||||
expect(translatedString).to.not.be.empty;
|
||||
expect(translatedString).to.not.eql(STRING_ERROR_MSG);
|
||||
|
|
|
|||
|
|
@ -113,8 +113,10 @@
|
|||
"sentGems": "Sent gems!",
|
||||
"giftedGems": "Gifted Gems",
|
||||
"giftedGemsInfo": "<%= name %> gifted you <%= amount %> Gems",
|
||||
"giftedGemsFull": "Hello <%= username %>, <%= sender %> has sent you <%= gemAmount %> gems!",
|
||||
"giftedSubscription": "Gifted Subscription",
|
||||
"giftedSubscriptionInfo": "<%= name %> gifted you a <%= months %> month subscription",
|
||||
"giftedSubscriptionFull": "Hello <%= username %>, <%= sender %> has sent you <%= monthCount %> months of subscription!",
|
||||
"invitedParty": "Invited To Party",
|
||||
"invitedGuild": "Invited To Guild",
|
||||
"importantAnnouncements": "Your account is inactive",
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ api.sendPrivateMessage = {
|
|||
throw new NotAuthorized(res.t('notAuthorizedToSendMessageToThisUser'));
|
||||
}
|
||||
|
||||
await sender.sendMessage(receiver, message);
|
||||
await sender.sendMessage(receiver, { receiverMsg: message });
|
||||
|
||||
if (receiver.preferences.emailNotifications.newPM !== false) {
|
||||
sendTxnEmail(receiver, 'new-pm', [
|
||||
|
|
@ -492,18 +492,27 @@ api.transferGems = {
|
|||
let promises = [receiver.save(), sender.save()];
|
||||
await Bluebird.all(promises);
|
||||
|
||||
let message = res.t('privateMessageGiftIntro', {
|
||||
receiverName: receiver.profile.name,
|
||||
senderName: sender.profile.name,
|
||||
// generate the message in both languages, so both users can understand it
|
||||
let receiverLang = receiver.preferences.language;
|
||||
let senderLang = sender.preferences.language;
|
||||
let [receiverMsg, senderMsg] = [receiverLang, senderLang].map((lang) => {
|
||||
let messageContent = res.t('privateMessageGiftIntro', {
|
||||
receiverName: receiver.profile.name,
|
||||
senderName: sender.profile.name,
|
||||
}, lang);
|
||||
messageContent += res.t('privateMessageGiftGemsMessage', {gemAmount}, lang);
|
||||
messageContent = `\`${messageContent}\` `;
|
||||
|
||||
if (req.body.message) {
|
||||
messageContent += req.body.message;
|
||||
}
|
||||
return messageContent;
|
||||
});
|
||||
message += res.t('privateMessageGiftGemsMessage', {gemAmount});
|
||||
message = `\`${message}\` `;
|
||||
|
||||
if (req.body.message) {
|
||||
message += req.body.message;
|
||||
}
|
||||
|
||||
await sender.sendMessage(receiver, message);
|
||||
await sender.sendMessage(receiver, {
|
||||
senderMsg,
|
||||
receiverMsg,
|
||||
});
|
||||
|
||||
let byUsername = getUserInfo(sender, ['name']).name;
|
||||
|
||||
|
|
@ -516,8 +525,8 @@ api.transferGems = {
|
|||
if (receiver.preferences.pushNotifications.giftedGems !== false) {
|
||||
sendPushNotification(receiver,
|
||||
{
|
||||
title: res.t('giftedGems'),
|
||||
message: res.t('giftedGemsInfo', {amount: gemAmount, name: byUsername}),
|
||||
title: res.t('giftedGems', receiverLang),
|
||||
message: res.t('giftedGemsInfo', {amount: gemAmount, name: byUsername}, receiverLang),
|
||||
identifier: 'giftedGems',
|
||||
payload: {replyTo: sender._id},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -138,13 +138,31 @@ api.createSubscription = async function createSubscription (data) {
|
|||
if (!group) data.user.purchased.txnCount++;
|
||||
|
||||
if (data.gift) {
|
||||
let message = `\`Hello ${data.gift.member.profile.name}, ${data.user.profile.name} has sent you ${shared.content.subscriptionBlocks[data.gift.subscription.key].months} months of subscription!\``;
|
||||
if (data.gift.message) message += ` ${data.gift.message}`;
|
||||
|
||||
data.user.sendMessage(data.gift.member, message);
|
||||
|
||||
let byUserName = getUserInfo(data.user, ['name']).name;
|
||||
|
||||
// generate the message in both languages, so both users can understand it
|
||||
let languages = [data.user.preferences.language, data.gift.member.preferences.language];
|
||||
let senderMsg = shared.i18n.t('giftedSubscriptionFull', {
|
||||
username: data.gift.member.profile.name,
|
||||
sender: byUserName,
|
||||
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
|
||||
}, languages[0]);
|
||||
senderMsg = `\`${senderMsg}\``;
|
||||
|
||||
let receiverMsg = shared.i18n.t('giftedSubscriptionFull', {
|
||||
username: data.gift.member.profile.name,
|
||||
sender: byUserName,
|
||||
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
|
||||
}, languages[1]);
|
||||
receiverMsg = `\`${receiverMsg}\``;
|
||||
|
||||
if (data.gift.message) {
|
||||
receiverMsg += ` ${data.gift.message}`;
|
||||
senderMsg += ` ${data.gift.message}`;
|
||||
}
|
||||
|
||||
data.user.sendMessage(data.gift.member, { receiverMsg, senderMsg });
|
||||
|
||||
if (data.gift.member.preferences.emailNotifications.giftedSubscription !== false) {
|
||||
txnEmail(data.gift.member, 'gifted-subscription', [
|
||||
{name: 'GIFTER', content: byUserName},
|
||||
|
|
@ -156,8 +174,8 @@ api.createSubscription = async function createSubscription (data) {
|
|||
if (data.gift.member.preferences.pushNotifications.giftedSubscription !== false) {
|
||||
sendPushNotification(data.gift.member,
|
||||
{
|
||||
title: shared.i18n.t('giftedSubscription'),
|
||||
message: shared.i18n.t('giftedSubscriptionInfo', {months, name: byUserName}),
|
||||
title: shared.i18n.t('giftedSubscription', languages[1]),
|
||||
message: shared.i18n.t('giftedSubscriptionInfo', {months, name: byUserName}, languages[1]),
|
||||
identifier: 'giftedSubscription',
|
||||
payload: {replyTo: data.user._id},
|
||||
}
|
||||
|
|
@ -276,9 +294,28 @@ api.buyGems = async function buyGems (data) {
|
|||
let byUsername = getUserInfo(data.user, ['name']).name;
|
||||
let gemAmount = data.gift.gems.amount || 20;
|
||||
|
||||
let message = `\`Hello ${data.gift.member.profile.name}, ${data.user.profile.name} has sent you ${gemAmount} gems!\``;
|
||||
if (data.gift.message) message += ` ${data.gift.message}`;
|
||||
data.user.sendMessage(data.gift.member, message);
|
||||
// generate the message in both languages, so both users can understand it
|
||||
let languages = [data.user.preferences.language, data.gift.member.preferences.language];
|
||||
let senderMsg = shared.i18n.t('giftedGemsFull', {
|
||||
username: data.gift.member.profile.name,
|
||||
sender: byUsername,
|
||||
gemAmount,
|
||||
}, languages[0]);
|
||||
senderMsg = `\`${senderMsg}\``;
|
||||
|
||||
let receiverMsg = shared.i18n.t('giftedGemsFull', {
|
||||
username: data.gift.member.profile.name,
|
||||
sender: byUsername,
|
||||
gemAmount,
|
||||
}, languages[1]);
|
||||
receiverMsg = `\`${receiverMsg}\``;
|
||||
|
||||
if (data.gift.message) {
|
||||
receiverMsg += ` ${data.gift.message}`;
|
||||
senderMsg += ` ${data.gift.message}`;
|
||||
}
|
||||
|
||||
data.user.sendMessage(data.gift.member, { receiverMsg, senderMsg });
|
||||
|
||||
if (data.gift.member.preferences.emailNotifications.giftedGems !== false) {
|
||||
txnEmail(data.gift.member, 'gifted-gems', [
|
||||
|
|
@ -292,8 +329,8 @@ api.buyGems = async function buyGems (data) {
|
|||
sendPushNotification(
|
||||
data.gift.member,
|
||||
{
|
||||
title: shared.i18n.t('giftedGems'),
|
||||
message: shared.i18n.t('giftedGemsInfo', {amount: gemAmount, name: byUsername}),
|
||||
title: shared.i18n.t('giftedGems', languages[1]),
|
||||
message: shared.i18n.t('giftedGemsInfo', {amount: gemAmount, name: byUsername}, languages[1]),
|
||||
identifier: 'giftedGems',
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -20,15 +20,26 @@ schema.methods.getGroups = function getUserGroups () {
|
|||
return userGroups;
|
||||
};
|
||||
|
||||
schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, message) {
|
||||
let sender = this;
|
||||
|
||||
common.refPush(userToReceiveMessage.inbox.messages, chatDefaults(message, sender));
|
||||
/**
|
||||
* Sends a message to a user. Archives a copy in sender's inbox.
|
||||
*
|
||||
* @param userToReceiveMessage The receiver
|
||||
* @param options
|
||||
* @param options.receiverMsg The message to send to the receiver
|
||||
* @param options.senderMsg The message to archive instead of receiverMsg
|
||||
* @return N/A
|
||||
*/
|
||||
schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, options) {
|
||||
let sender = this;
|
||||
let senderMsg = options.senderMsg || options.receiverMsg;
|
||||
|
||||
common.refPush(userToReceiveMessage.inbox.messages, chatDefaults(options.receiverMsg, sender));
|
||||
userToReceiveMessage.inbox.newMessages++;
|
||||
userToReceiveMessage._v++;
|
||||
userToReceiveMessage.markModified('inbox.messages');
|
||||
|
||||
common.refPush(sender.inbox.messages, defaults({sent: true}, chatDefaults(message, userToReceiveMessage)));
|
||||
common.refPush(sender.inbox.messages, defaults({sent: true}, chatDefaults(senderMsg, userToReceiveMessage)));
|
||||
sender.markModified('inbox.messages');
|
||||
|
||||
let promises = [userToReceiveMessage.save(), sender.save()];
|
||||
|
|
|
|||
Loading…
Reference in a new issue