From cdec3e26445eef5d39fb108c00f41c8cdede8c24 Mon Sep 17 00:00:00 2001 From: Domagoj Kriskovic Date: Thu, 12 Jun 2025 13:19:18 +0200 Subject: [PATCH] Add permissions checks for AI assist addon purchase (#26355) * Add permissions checks for AI assist when trying to buy the addon * more explicit check for DuplicateAddOnError * remove useCapabilities() GitOrigin-RevId: 1979e27410981e2ef020cecc731e228483d3315a --- .../Subscription/SubscriptionController.js | 14 +++++++++++++- services/web/frontend/extracted-translations.json | 1 + .../components/dashboard/free-plan.tsx | 2 -- .../components/dashboard/personal-subscription.tsx | 2 -- .../components/dashboard/redirect-alerts.tsx | 2 ++ .../dashboard/subscription-dashboard.tsx | 2 ++ services/web/locales/en.json | 1 + 7 files changed, 19 insertions(+), 5 deletions(-) diff --git a/services/web/app/src/Features/Subscription/SubscriptionController.js b/services/web/app/src/Features/Subscription/SubscriptionController.js index d7de79f5a4..41b8eac017 100644 --- a/services/web/app/src/Features/Subscription/SubscriptionController.js +++ b/services/web/app/src/Features/Subscription/SubscriptionController.js @@ -32,6 +32,7 @@ const PlansLocator = require('./PlansLocator') const PaymentProviderEntities = require('./PaymentProviderEntities') const { User } = require('../../models/User') const UserGetter = require('../User/UserGetter') +const PermissionsManager = require('../Authorization/PermissionsManager') /** * @import { SubscriptionChangeDescription } from '../../../../types/subscription/subscription-change-preview' @@ -336,7 +337,8 @@ function cancelV1Subscription(req, res, next) { } async function previewAddonPurchase(req, res) { - const userId = SessionManager.getLoggedInUserId(req.session) + const user = SessionManager.getSessionUser(req.session) + const userId = user._id const addOnCode = req.params.addOnCode const purchaseReferrer = req.query.purchaseReferrer @@ -344,6 +346,16 @@ async function previewAddonPurchase(req, res) { return HttpErrorHandler.notFound(req, res, `Unknown add-on: ${addOnCode}`) } + const canUseAi = await PermissionsManager.promises.checkUserPermissions( + user, + ['use-ai'] + ) + if (!canUseAi) { + return res.redirect( + '/user/subscription?redirect-reason=ai-assist-unavailable' + ) + } + /** @type {PaymentMethod[]} */ const paymentMethod = await Modules.promises.hooks.fire( 'getPaymentMethod', diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index e38bfbe44b..6067638734 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -109,6 +109,7 @@ "agree_with_the_terms": "", "ai_assist_in_overleaf_is_included_via_writefull_groups": "", "ai_assist_in_overleaf_is_included_via_writefull_individual": "", + "ai_assist_unavailable_due_to_subscription_type": "", "ai_assistance_to_help_you": "", "ai_based_language_tools": "", "ai_can_make_mistakes": "", diff --git a/services/web/frontend/js/features/subscription/components/dashboard/free-plan.tsx b/services/web/frontend/js/features/subscription/components/dashboard/free-plan.tsx index a8cf7dcf7b..1f9583dd8b 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/free-plan.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/free-plan.tsx @@ -1,6 +1,5 @@ import { useTranslation, Trans } from 'react-i18next' import WritefullManagedBundleAddOn from '@/features/subscription/components/dashboard/states/active/change-plan/modals/writefull-bundle-management-modal' -import RedirectAlerts from './redirect-alerts' import getMeta from '@/utils/meta' function FreePlan() { @@ -9,7 +8,6 @@ function FreePlan() { return ( <> - - {personalSubscription.payment.hasPastDueInvoice && ( )} diff --git a/services/web/frontend/js/features/subscription/components/dashboard/redirect-alerts.tsx b/services/web/frontend/js/features/subscription/components/dashboard/redirect-alerts.tsx index be5bab484e..9dea4e1e46 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/redirect-alerts.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/redirect-alerts.tsx @@ -15,6 +15,8 @@ export function RedirectAlerts() { warning = t('good_news_you_are_already_receiving_this_add_on_via_writefull') } else if (redirectReason === 'double-buy') { warning = t('good_news_you_already_purchased_this_add_on') + } else if (redirectReason === 'ai-assist-unavailable') { + warning = t('ai_assist_unavailable_due_to_subscription_type') } else { return null } diff --git a/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx b/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx index 8cb07181cf..b0f1b4122c 100644 --- a/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx +++ b/services/web/frontend/js/features/subscription/components/dashboard/subscription-dashboard.tsx @@ -15,6 +15,7 @@ import OLRow from '@/features/ui/components/ol/ol-row' import OLCol from '@/features/ui/components/ol/ol-col' import OLNotification from '@/features/ui/components/ol/ol-notification' import WritefullManagedBundleAddOn from './states/active/change-plan/modals/writefull-bundle-management-modal' +import RedirectAlerts from './redirect-alerts' function SubscriptionDashboard() { const { t } = useTranslation() @@ -40,6 +41,7 @@ function SubscriptionDashboard() { type="warning" /> )} +

{t('your_subscription')}

diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 9380eb4834..fd4a0953f6 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -130,6 +130,7 @@ "agree_with_the_terms": "I agree with the Overleaf terms", "ai_assist_in_overleaf_is_included_via_writefull_groups": "AI Assist in Overleaf is included as part of your group or organization’s Writefull subscription. To make changes you’ll need to speak to your subscription admin", "ai_assist_in_overleaf_is_included_via_writefull_individual": "AI Assist in Overleaf is included as part of your Writefull subscription. You can cancel or manage your access to AI Assist in your Writefull subscription settings.", + "ai_assist_unavailable_due_to_subscription_type": "We’re sorry—it looks like AI Assist isn’t available to you just yet due to your current subscription type.", "ai_assistance_to_help_you": "AI assistance to help you fix LaTeX errors", "ai_based_language_tools": "AI-based language tools tailored to research writing", "ai_can_make_mistakes": "AI can make mistakes. Review fixes before you apply them.",