diff --git a/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs b/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs index b6c56087cc..3f4d8d3e88 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs +++ b/services/web/app/src/Features/Subscription/SubscriptionLocator.mjs @@ -71,17 +71,19 @@ const SubscriptionLocator = { return subscription?.admin_id }, - async hasGroupSubscription(userOrId) { - if (!Features.hasFeature('saas')) return false + async getAllAssociatedSubscriptions(userOrId, projection = {}) { + if (!Features.hasFeature('saas')) return [] const userId = SubscriptionLocator._getUserId(userOrId) - return await Subscription.exists({ - groupPlan: true, - $or: [ - { member_ids: userId }, - { manager_ids: userId }, - { admin_id: userId }, - ], - }).exec() + return await Subscription.find( + { + $or: [ + { admin_id: userId }, + { manager_ids: userId }, + { member_ids: userId }, + ], + }, + projection + ).exec() }, async getSubscription(subscriptionId) { diff --git a/services/web/app/src/Features/Survey/SurveyHandler.mjs b/services/web/app/src/Features/Survey/SurveyHandler.mjs index 767c351b09..6e6261f453 100644 --- a/services/web/app/src/Features/Survey/SurveyHandler.mjs +++ b/services/web/app/src/Features/Survey/SurveyHandler.mjs @@ -3,6 +3,7 @@ import crypto from 'node:crypto' import SurveyCache from './SurveyCache.mjs' import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs' +import PlansHelper from '../Subscription/PlansHelper.mjs' import { callbackify } from '@overleaf/promise-utils' import UserGetter from '../User/UserGetter.mjs' @@ -19,10 +20,31 @@ import UserGetter from '../User/UserGetter.mjs' async function getSurvey(userId) { const survey = await SurveyCache.get(true) if (survey) { - if (survey.options?.hasGroupSubscription) { - const hasGroupSubscription = - await SubscriptionLocator.promises.hasGroupSubscription(userId) - if (!hasGroupSubscription) { + const hasFilters = + survey.options.hasFreeSubscription || + survey.options.hasIndividualStandardSubscription || + survey.options.hasIndividualProfessionalSubscription || + survey.options.hasGroupStandardSubscription || + survey.options.hasGroupProfessionalSubscription + + if (hasFilters) { + const subscriptions = + await SubscriptionLocator.promises.getAllAssociatedSubscriptions( + userId, + { + groupPlan: 1, + planCode: 1, + } + ) + const isFreeSubscription = Boolean(!subscriptions?.length) + + if (isFreeSubscription) { + if (!survey.options?.hasFreeSubscription) { + return + } + } else if ( + !subscriptions.some(sub => _canDisplaySurvey(sub, survey.options)) + ) { return } } @@ -64,6 +86,24 @@ async function getSurvey(userId) { } } +function _canDisplaySurvey(subscription, options = {}) { + const { + hasIndividualStandardSubscription, + hasIndividualProfessionalSubscription, + hasGroupStandardSubscription, + hasGroupProfessionalSubscription, + } = options + const isGroupPlan = subscription.groupPlan + const isProfessional = PlansHelper.isProfessionalPlan(subscription.planCode) + + return ( + (hasIndividualStandardSubscription && !isGroupPlan && !isProfessional) || + (hasIndividualProfessionalSubscription && !isGroupPlan && isProfessional) || + (hasGroupStandardSubscription && isGroupPlan && !isProfessional) || + (hasGroupProfessionalSubscription && isGroupPlan && isProfessional) + ) +} + function _userRolloutPercentile(userId, surveyName) { const hash = crypto .createHash('md5') diff --git a/services/web/app/src/models/Survey.mjs b/services/web/app/src/models/Survey.mjs index 4261d5ae87..8ce1bbe55d 100644 --- a/services/web/app/src/models/Survey.mjs +++ b/services/web/app/src/models/Survey.mjs @@ -36,7 +36,23 @@ export const SurveySchema = new Schema( required: true, }, options: { - hasGroupSubscription: { + hasFreeSubscription: { + type: Boolean, + default: false, + }, + hasIndividualStandardSubscription: { + type: Boolean, + default: false, + }, + hasIndividualProfessionalSubscription: { + type: Boolean, + default: false, + }, + hasGroupStandardSubscription: { + type: Boolean, + default: false, + }, + hasGroupProfessionalSubscription: { type: Boolean, default: false, },