mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 05:07:22 +01:00
* refactor sending jobs to worker server * remove unused imports * add delete button to adminpanel * June 2025 content build (#15437) * chore: June 2025 content build * chore: typo fixing * chore: corrections to summer 2025 mage armor, spritesheet * fix(css): rebuild spritesmith-main --------- Co-authored-by: Kalista Payne <sabrecat@gmail.com> * fix(script): don't use extremely costly regex * fix(logging): don't spam empty error events * Translated using Weblate (Ukrainian) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (280 of 280 strings) Translated using Weblate (French) Currently translated at 100.0% (280 of 280 strings) Translated using Weblate (Spanish) Currently translated at 99.6% (279 of 280 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.4% (840 of 862 strings) Translated using Weblate (German) Currently translated at 99.8% (907 of 908 strings) Translated using Weblate (Dutch) Currently translated at 79.3% (219 of 276 strings) Translated using Weblate (Dutch) Currently translated at 28.1% (69 of 245 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.4% (840 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.5% (402 of 412 strings) Translated using Weblate (Dutch) Currently translated at 91.5% (377 of 412 strings) Translated using Weblate (Dutch) Currently translated at 85.2% (774 of 908 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Slovak) Currently translated at 63.4% (106 of 167 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Slovak) Currently translated at 2.0% (5 of 245 strings) Translated using Weblate (French) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Russian) Currently translated at 64.4% (158 of 245 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.0% (837 of 862 strings) Translated using Weblate (German) Currently translated at 97.9% (844 of 862 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.3% (401 of 412 strings) Translated using Weblate (Portuguese) Currently translated at 95.3% (393 of 412 strings) Translated using Weblate (Slovak) Currently translated at 45.6% (413 of 905 strings) Translated using Weblate (Slovak) Currently translated at 50.8% (85 of 167 strings) Translated using Weblate (Russian) Currently translated at 99.1% (113 of 114 strings) Translated using Weblate (Russian) Currently translated at 64.0% (157 of 245 strings) Translated using Weblate (Russian) Currently translated at 64.0% (157 of 245 strings) Translated using Weblate (Russian) Currently translated at 62.0% (152 of 245 strings) Translated using Weblate (Russian) Currently translated at 62.0% (152 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.8% (149 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.8% (149 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.4% (148 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.4% (148 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.0% (147 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.0% (147 of 245 strings) Translated using Weblate (Russian) Currently translated at 57.9% (142 of 245 strings) Translated using Weblate (Russian) Currently translated at 57.9% (142 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.7% (139 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.7% (139 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.3% (138 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.3% (138 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.8% (132 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.8% (132 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.4% (131 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.4% (131 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.9% (120 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.9% (120 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.5% (119 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.5% (119 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (German) Currently translated at 99.9% (3324 of 3325 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.8% (107 of 114 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (22 of 22 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.7% (429 of 430 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.6% (902 of 905 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Portuguese) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.8% (107 of 114 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.6% (3114 of 3325 strings) Translated using Weblate (Portuguese) Currently translated at 53.9% (1793 of 3325 strings) Translated using Weblate (Dutch) Currently translated at 78.1% (2600 of 3325 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.5% (242 of 243 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 96.6% (398 of 412 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.6% (902 of 905 strings) Translated using Weblate (Italian) Currently translated at 99.1% (113 of 114 strings) Translated using Weblate (Italian) Currently translated at 87.3% (2903 of 3325 strings) Translated using Weblate (Italian) Currently translated at 17.1% (42 of 245 strings) Translated using Weblate (Italian) Currently translated at 99.0% (408 of 412 strings) Translated using Weblate (Italian) Currently translated at 92.7% (102 of 110 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.0% (3292 of 3325 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.7% (3285 of 3325 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.7% (3285 of 3325 strings) Translated using Weblate (Slovak) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (Slovak) Currently translated at 100.0% (412 of 412 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (905 of 905 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.1% (3262 of 3325 strings) Co-authored-by: Andrea <goffopaguro@gmail.com> Co-authored-by: Artem StolyROV <stolyarov11303@gmail.com> Co-authored-by: Céu <marcel.ufscar@gmail.com> Co-authored-by: David Kaya <david@kaya.sk> Co-authored-by: Filip Betko <filipbetko@gmail.com> Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Irina Shcherbinina <cat3dcat007@gmail.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Mencius <beautyalinap@gmail.com> Co-authored-by: Natalie Luhrs <eilatan@gmail.com> Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: Summer_GUI <heyang94@163.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Tom <tompsognathus@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: V Aar <v.vanderaar@gmail.com> Co-authored-by: Viktor Révész <rviktor@ivankapal.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: razil <boss.razmarin@gmail.com> Co-authored-by: Волкозмей <klippiky@gmail.com> Co-authored-by: Данила Мальцев <maltsev-danila@inbox.ru> Co-authored-by: Татьяна Куклева <klippiky@gmail.com> Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/hu/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/challenge/it/ Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/content/it/ Translate-URL: https://translate.habitica.com/projects/habitica/content/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/content/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/content/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/hu/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/it/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/ru/ Translate-URL: https://translate.habitica.com/projects/habitica/quests/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/ Translation: Habitica/Achievements Translation: Habitica/Backgrounds Translation: Habitica/Challenge Translation: Habitica/Communityguidelines Translation: Habitica/Content Translation: Habitica/Faq Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Groups Translation: Habitica/Limited Translation: Habitica/Loginincentives Translation: Habitica/Npc Translation: Habitica/Pets Translation: Habitica/Quests Translation: Habitica/Questscontent * 5.36.4 * chore(deps): bump serialize-javascript in /website/client (#15395) Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/yahoo/serialize-javascript/releases) - [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: serialize-javascript dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump axios from 1.7.4 to 1.8.2 (#15401) Bumps [axios](https://github.com/axios/axios) from 1.7.4 to 1.8.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.7.4...v1.8.2) --- updated-dependencies: - dependency-name: axios dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump prismjs from 1.29.0 to 1.30.0 (#15403) Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0. - [Release notes](https://github.com/PrismJS/prism/releases) - [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md) - [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0) --- updated-dependencies: - dependency-name: prismjs dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/runtime-corejs2 in /website/client (#15406) Bumps [@babel/runtime-corejs2](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs2) from 7.23.6 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime-corejs2) --- updated-dependencies: - dependency-name: "@babel/runtime-corejs2" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/helpers in /website/client (#15407) Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.23.6 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers) --- updated-dependencies: - dependency-name: "@babel/helpers" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/runtime from 7.23.9 to 7.26.10 (#15410) Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.23.9 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump http-proxy-middleware in /website/client (#15427) Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.6 to 2.0.9. - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases) - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.9/CHANGELOG.md) - [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.6...v2.0.9) --- updated-dependencies: - dependency-name: http-proxy-middleware dependency-version: 2.0.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Optimize database access for some use cases (#15444) * optimize query when listing challenge tasks * Optimize query for checking if user is party leader * correct worker call * remove unused priority * fix tests * don’t use body with delete * add detailed information about sub payment for google and apple * Support paypal details for subscription in admin panel * stripe payment details * fix imports * fix tests * fix deleting account * begin building group admin panel * fix convertig sub to group plan * improve sub status display * fix lint * fix long line * fix sub state display * lint fix * fix * delete amplitude data by default * improve searching for email in admin panel * correctly call method * move delete button in admin panel * fix(lint): whitespace * fix(style): indent * fix(typo): humand --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com> Co-authored-by: Kalista Payne <sabrecat@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Andrea <goffopaguro@gmail.com> Co-authored-by: Artem StolyROV <stolyarov11303@gmail.com> Co-authored-by: Céu <marcel.ufscar@gmail.com> Co-authored-by: David Kaya <david@kaya.sk> Co-authored-by: Filip Betko <filipbetko@gmail.com> Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Irina Shcherbinina <cat3dcat007@gmail.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Mencius <beautyalinap@gmail.com> Co-authored-by: Natalie Luhrs <eilatan@gmail.com> Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: Summer_GUI <heyang94@163.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Tom <tompsognathus@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: V Aar <v.vanderaar@gmail.com> Co-authored-by: Viktor Révész <rviktor@ivankapal.com> Co-authored-by: razil <boss.razmarin@gmail.com> Co-authored-by: Волкозмей <klippiky@gmail.com> Co-authored-by: Данила Мальцев <maltsev-danila@inbox.ru> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kalista Payne <kalista@habitica.com>
260 lines
9.4 KiB
JavaScript
260 lines
9.4 KiB
JavaScript
// TODO these files need to refactored.
|
|
|
|
import nconf from 'nconf';
|
|
import _ from 'lodash';
|
|
import moment from 'moment';
|
|
|
|
import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle
|
|
import * as Tasks from '../../models/task'; // eslint-disable-line import/no-cycle
|
|
import { // eslint-disable-line import/no-cycle
|
|
model as Group,
|
|
basicFields as basicGroupFields,
|
|
} from '../../models/group';
|
|
import { // eslint-disable-line import/no-cycle
|
|
getUserInfo,
|
|
sendTxn as txnEmail,
|
|
} from '../email';
|
|
import { paymentConstants } from './constants';
|
|
import { cancelSubscription, createSubscription } from './subscriptions'; // eslint-disable-line import/no-cycle
|
|
|
|
const TECH_ASSISTANCE_EMAIL = nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL');
|
|
const JOINED_GROUP_PLAN = 'joined group plan';
|
|
|
|
function _dateDiff (earlyDate, lateDate) {
|
|
if (!earlyDate || !lateDate || moment(lateDate).isBefore(earlyDate)) return 0;
|
|
|
|
return moment(lateDate).diff(earlyDate, 'months', true);
|
|
}
|
|
|
|
/**
|
|
* Add a subscription to members of a group
|
|
*
|
|
* @param group The Group Model that is subscribed to a group plan
|
|
*
|
|
* @return undefined
|
|
*/
|
|
async function addSubscriptionToGroupUsers (group) {
|
|
let members;
|
|
if (group.type === 'guild') {
|
|
members = await User.find({ guilds: group._id }).select('_id purchased items auth profile.name notifications').exec();
|
|
} else {
|
|
members = await User.find({ 'party._id': group._id }).select('_id purchased items auth profile.name notifications').exec();
|
|
}
|
|
|
|
// eslint-disable-next-line no-use-before-define
|
|
const promises = members.map(member => addSubToGroupUser(member, group));
|
|
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
/**
|
|
* Add a subscription to a new member of a group
|
|
*
|
|
* @param member The new member of the group
|
|
*
|
|
* @return undefined
|
|
*/
|
|
async function addSubToGroupUser (member, group) {
|
|
// These EMAIL_TEMPLATE constants are used to pass strings into templates that are
|
|
// stored externally and so their values must not be changed.
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE = 'Google_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_IOS = 'iOS_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GROUP_PLAN = 'group_plan_free_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_LIFETIME_FREE = 'lifetime_free_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL = 'normal_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_UNKNOWN = 'unknown_type_of_subscription';
|
|
const EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE = 'no_subscription';
|
|
|
|
// When changing customerIdsToIgnore or paymentMethodsToIgnore, the code blocks below for
|
|
// the `group-member-join` email template will probably need to be changed.
|
|
const customerIdsToIgnore = [
|
|
paymentConstants.GROUP_PLAN_CUSTOMER_ID,
|
|
paymentConstants.UNLIMITED_CUSTOMER_ID,
|
|
];
|
|
const paymentMethodsToIgnore = [
|
|
paymentConstants.GOOGLE_PAYMENT_METHOD,
|
|
paymentConstants.IOS_PAYMENT_METHOD,
|
|
];
|
|
let previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NONE;
|
|
const leader = await User.findById(group.leader).exec();
|
|
|
|
const data = {
|
|
user: {},
|
|
sub: {
|
|
key: 'group_plan_auto',
|
|
},
|
|
customerId: 'group-plan',
|
|
paymentMethod: 'Group Plan',
|
|
headers: {},
|
|
};
|
|
|
|
let plan = {
|
|
planId: 'group_plan_auto',
|
|
customerId: 'group-plan',
|
|
dateUpdated: new Date(),
|
|
gemsBought: 0,
|
|
paymentMethod: 'groupPlan',
|
|
extraMonths: 0,
|
|
dateTerminated: null,
|
|
lastBillingDate: null,
|
|
dateCreated: member.purchased.plan.dateCreated || new Date(),
|
|
mysteryItems: [],
|
|
consecutive: {
|
|
trinkets: 0,
|
|
offset: 0,
|
|
gemCapExtra: 0,
|
|
},
|
|
};
|
|
|
|
const memberPlan = member.purchased.plan;
|
|
if (member.isSubscribed()) {
|
|
const customerHasCancelledGroupPlan = (
|
|
memberPlan.customerId === paymentConstants.GROUP_PLAN_CUSTOMER_ID
|
|
&& !member.hasNotCancelled()
|
|
);
|
|
const ignorePaymentPlan = paymentMethodsToIgnore.indexOf(memberPlan.paymentMethod) !== -1;
|
|
const ignoreCustomerId = customerIdsToIgnore.indexOf(memberPlan.customerId) !== -1;
|
|
|
|
if (ignorePaymentPlan) {
|
|
txnEmail({ email: TECH_ASSISTANCE_EMAIL }, 'admin-user-subscription-details', [
|
|
{ name: 'PROFILE_NAME', content: member.profile.name },
|
|
{ name: 'UUID', content: member._id },
|
|
{ name: 'EMAIL', content: getUserInfo(member, ['email']).email },
|
|
{ name: 'PAYMENT_METHOD', content: memberPlan.paymentMethod },
|
|
{ name: 'PURCHASED_PLAN', content: JSON.stringify(memberPlan) },
|
|
{ name: 'ACTION_NEEDED', content: 'User has joined group plan and has been told to cancel their subscription then email us. Ensure they do that then give them free sub.' },
|
|
// TODO User won't get email instructions if they've opted out of all emails.
|
|
// See if we can make this email an exception and if not,
|
|
// report here whether they've opted out.
|
|
]);
|
|
}
|
|
|
|
if ((ignorePaymentPlan || ignoreCustomerId) && !customerHasCancelledGroupPlan) {
|
|
// member has been added to group plan but their subscription will not be changed
|
|
// automatically so they need a special message in the email
|
|
if (memberPlan.paymentMethod === paymentConstants.GOOGLE_PAYMENT_METHOD) {
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GOOGLE;
|
|
} else if (memberPlan.paymentMethod === paymentConstants.IOS_PAYMENT_METHOD) {
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_IOS;
|
|
} else if (memberPlan.customerId === paymentConstants.UNLIMITED_CUSTOMER_ID) {
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_LIFETIME_FREE;
|
|
} else if (memberPlan.customerId === paymentConstants.GROUP_PLAN_CUSTOMER_ID) {
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_GROUP_PLAN;
|
|
} else {
|
|
// this triggers a generic message in the email template in case we forget
|
|
// to update this code for new special cases
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_UNKNOWN;
|
|
}
|
|
txnEmail(member, 'group-member-join', [
|
|
{ name: 'LEADER', content: leader.profile.name },
|
|
{ name: 'GROUP_NAME', content: group.name },
|
|
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: previousSubscriptionType },
|
|
]);
|
|
return;
|
|
}
|
|
|
|
if (member.hasNotCancelled()) {
|
|
await member.cancelSubscription({ cancellationReason: JOINED_GROUP_PLAN });
|
|
previousSubscriptionType = EMAIL_TEMPLATE_SUBSCRIPTION_TYPE_NORMAL;
|
|
}
|
|
|
|
const today = new Date();
|
|
plan = member.purchased.plan.toObject();
|
|
let extraMonths = Number(plan.extraMonths);
|
|
if (plan.dateTerminated) extraMonths += _dateDiff(today, plan.dateTerminated);
|
|
|
|
_(plan).merge({ // override with these values
|
|
planId: 'group_plan_auto',
|
|
customerId: 'group-plan',
|
|
dateUpdated: today,
|
|
paymentMethod: 'groupPlan',
|
|
extraMonths,
|
|
dateTerminated: null,
|
|
lastBillingDate: null,
|
|
owner: member._id,
|
|
}).defaults({ // allow non-override if a plan was previously used
|
|
gemsBought: 0,
|
|
dateCreated: today,
|
|
mysteryItems: [],
|
|
}).value();
|
|
}
|
|
|
|
// save unused hourglass and mystery items
|
|
plan.consecutive.trinkets = memberPlan.consecutive.trinkets;
|
|
plan.mysteryItems = memberPlan.mysteryItems;
|
|
|
|
member.purchased.plan = plan;
|
|
member.items.mounts['Jackalope-RoyalPurple'] = true;
|
|
member.markModified('items.mounts');
|
|
|
|
data.user = member;
|
|
await createSubscription(data);
|
|
|
|
txnEmail(data.user, 'group-member-join', [
|
|
{ name: 'LEADER', content: leader.profile.name },
|
|
{ name: 'GROUP_NAME', content: group.name },
|
|
{ name: 'PREVIOUS_SUBSCRIPTION_TYPE', content: previousSubscriptionType },
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Cancels subscriptions of members of a group
|
|
*
|
|
* @param group The Group Model that is cancelling a group plan
|
|
*
|
|
* @return undefined
|
|
*/
|
|
async function cancelGroupUsersSubscription (group) {
|
|
let members;
|
|
if (group.type === 'guild') {
|
|
members = await User.find({ guilds: group._id }).select('_id guilds purchased').exec();
|
|
} else {
|
|
members = await User.find({ 'party._id': group._id }).select('_id guilds purchased').exec();
|
|
}
|
|
|
|
// eslint-disable-next-line no-use-before-define
|
|
const promises = members.map(member => cancelGroupSubscriptionForUser(member, group));
|
|
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
async function cancelGroupSubscriptionForUser (user, group, userWasRemoved = false) {
|
|
if (user.purchased.plan.customerId !== paymentConstants.GROUP_PLAN_CUSTOMER_ID) return;
|
|
|
|
const userGroups = user.guilds.toObject();
|
|
if (user.party._id) userGroups.push(user.party._id);
|
|
|
|
const index = userGroups.indexOf(group._id);
|
|
if (index >= 0) userGroups.splice(index, 1);
|
|
|
|
await Tasks.Task.deleteMany({ userId: user._id, 'group.id': group._id }).exec();
|
|
|
|
const groupPlansQuery = {
|
|
// type: { $in: ['guild', 'party'] },
|
|
// privacy: 'private',
|
|
_id: { $in: userGroups },
|
|
'purchased.plan.dateTerminated': { $type: 'null' },
|
|
};
|
|
|
|
const groupFields = `${basicGroupFields} purchased`;
|
|
const userGroupPlans = await Group.find(groupPlansQuery).select(groupFields).exec();
|
|
|
|
if (userGroupPlans.length === 0) {
|
|
const leader = await User.findById(group.leader).exec();
|
|
const email = userWasRemoved ? 'group-member-removed' : 'group-member-cancel';
|
|
|
|
txnEmail(user, email, [
|
|
{ name: 'LEADER', content: leader.profile.name },
|
|
{ name: 'GROUP_NAME', content: group.name },
|
|
]);
|
|
await cancelSubscription({ user });
|
|
}
|
|
}
|
|
|
|
export {
|
|
addSubscriptionToGroupUsers,
|
|
addSubToGroupUser,
|
|
cancelGroupUsersSubscription,
|
|
cancelGroupSubscriptionForUser,
|
|
};
|