diff --git a/README.md b/README.md index ecfdc18d4d..fc2ed27d08 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/website/server/libs/auth/index.js b/website/server/libs/auth/index.js index 5ee28cd800..76d37c1a47 100644 --- a/website/server/libs/auth/index.js +++ b/website/server/libs/auth/index.js @@ -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, }, diff --git a/website/server/libs/payments/groupPayments.js b/website/server/libs/payments/groupPayments.js index 92b167086a..ade378e81e 100644 --- a/website/server/libs/payments/groupPayments.js +++ b/website/server/libs/payments/groupPayments.js @@ -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); diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 4936e2b19e..39ee460a17 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -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) { diff --git a/website/server/models/user/methods.js b/website/server/models/user/methods.js index d9f478a932..9f37cd5fe0 100644 --- a/website/server/models/user/methods.js +++ b/website/server/models/user/methods.js @@ -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); + return true; }; schema.methods.isMemberOfGroupPlan = async function isMemberOfGroupPlan () {