Grant subscription to every user during registration and make first user an admin.

This commit is contained in:
Adrian Winterstein 2024-09-28 16:22:53 +02:00
parent 2242a46b31
commit 799ff58903
No known key found for this signature in database
GPG key ID: EDBA4B9F8D8E37AE
5 changed files with 11 additions and 65 deletions

View file

@ -12,6 +12,7 @@ The following noteworthy changes were applied to the Habitica source code:
- Dockerfile and Github Workflow to create the production containers for hosting
- every user automatically gets a subscription on registration that never needs to be renewed
- first registered used automatically gets admin rights
- locations for buying gems with money were replaced with options to buy with gold (e.g., the quick access in the header)
- group plans can be created without payment
- emails are sent directly via a configured SMTP server instead of using the Mailchimp (Mandrill) web-service

View file

@ -155,6 +155,14 @@ async function registerLocal (req, res, { isV3 = false }) {
passwordHashMethod: 'bcrypt',
},
},
'purchased.plan': {
planId: 'basic',
customerId: 'habitrpg',
dateCreated: new Date(),
dateUpdated: new Date(),
gemsBought: 0,
},
'permissions.fullAccess': ! await User.findOne().exec(), // admin access for the first registered user
preferences: {
language: req.language,
},

View file

@ -18,7 +18,6 @@ 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;
@ -61,7 +60,6 @@ async function addSubToGroupUser (member, group) {
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';
@ -153,11 +151,6 @@ async function addSubToGroupUser (member, group) {
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);

View file

@ -25,7 +25,6 @@ import { paymentConstants } from './constants';
import { addSubscriptionToGroupUsers, cancelGroupUsersSubscription } from './groupPayments'; // eslint-disable-line import/no-cycle
// @TODO: Abstract to shared/constant
const JOINED_GROUP_PLAN = 'joined group plan';
const analytics = getAnalyticsServiceByEnvironment();
function _findMysteryItems (user, dateMoment) {
@ -424,12 +423,7 @@ async function cancelSubscription (data) {
await cancelGroupUsersSubscription(group);
} else {
// cancelling a user subscription
plan = data.user.purchased.plan;
emailType = 'cancel-subscription';
// When cancelling because the user joined a group plan, no cancel-subscription email is sent
// because the group-member-join email says the subscription is cancelled.
if (data.cancellationReason && data.cancellationReason === JOINED_GROUP_PLAN) sendEmail = false;
return;
}
if (plan.customerId === paymentConstants.GROUP_PLAN_CUSTOMER_ID) {

View file

@ -18,11 +18,7 @@ import {
import { model as UserNotification } from '../userNotification';
import schema from './schema'; // eslint-disable-line import/no-cycle
import payments from '../../libs/payments/payments'; // eslint-disable-line import/no-cycle
import * as inboxLib from '../../libs/inbox'; // eslint-disable-line import/no-cycle
import amazonPayments from '../../libs/payments/amazon'; // eslint-disable-line import/no-cycle
import stripePayments from '../../libs/payments/stripe'; // eslint-disable-line import/no-cycle
import paypalPayments from '../../libs/payments/paypal'; // eslint-disable-line import/no-cycle
import { model as NewsPost } from '../newsPost';
import { TransactionModel as Transaction } from '../transaction';
@ -325,42 +321,6 @@ schema.statics.addComputedStatsToJSONObj = function addComputedStatsToUserJSONOb
return userStatsJSON;
};
/**
* Cancels a subscription.
*
* @param options
* @param options.user The user object who is purchasing
* @param options.groupId The id of the group purchasing a subscription
* @param options.headers The request headers (only for Amazon subscriptions)
* @param options.cancellationReason A text string to control sending an email
*
* @return a Promise from api.cancelSubscription()
*/
// @TODO: There is currently a three way relation between the user,
// payment methods and the payment helper
// This creates some odd Dependency Injection issues. To counter that,
// we use the user as the third layer
// To negotiate between the payment providers and the payment helper
// (which probably has too many responsibilities)
// In summary, currently is is best practice to use this method to cancel a user subscription,
// rather than calling the
// payment helper.
schema.methods.cancelSubscription = async function cancelSubscription (options = {}) {
const { plan } = this.purchased;
options.user = this;
if (plan.paymentMethod === amazonPayments.constants.PAYMENT_METHOD) {
return amazonPayments.cancelSubscription(options);
} if (plan.paymentMethod === stripePayments.constants.PAYMENT_METHOD) {
return stripePayments.cancelSubscription(options);
} if (plan.paymentMethod === paypalPayments.constants.PAYMENT_METHOD) {
return paypalPayments.subscribeCancel(options);
}
// Android and iOS subscriptions cannot be cancelled by Habitica.
return payments.cancelSubscription(options);
};
schema.methods.getUtcOffset = function getUtcOffset () {
return common.fns.getUtcOffset(this);
};
@ -489,17 +449,7 @@ async function getUserGroupData (user) {
// User is allowed to buy gems if no group has `leaderOnly.getGems` === true or if
// its the group leader
schema.methods.canGetGems = async function canObtainGems () {
const user = this;
const { plan } = user.purchased;
if (!user.isSubscribed() || plan.customerId !== payments.constants.GROUP_PLAN_CUSTOMER_ID) {
return true;
}
const groups = await getUserGroupData(user);
return groups
.every(g => !g.hasActiveGroupPlan() || g.leader === user._id || g.leaderOnly.getGems !== true);
};
schema.methods.isMemberOfGroupPlan = async function isMemberOfGroupPlan () {