|
|
@@ -18,6 +18,7 @@ import Modules from '../../infrastructure/Modules.mjs'
|
|
|
import SubscriptionViewModelBuilder from './SubscriptionViewModelBuilder.mjs'
|
|
|
import { AI_ADD_ON_CODE } from './AiHelper.mjs'
|
|
|
import { fetchNothing } from '@overleaf/fetch-utils'
|
|
|
+import SplitTestHandler from '../SplitTests/SplitTestHandler.mjs'
|
|
|
|
|
|
/**
|
|
|
* Enqueue a job for refreshing features for the given user
|
|
|
@@ -91,6 +92,19 @@ async function refreshFeatures(userId, reason) {
|
|
|
// skip if they are the reason we are refreshing features (they'd already be up to date)
|
|
|
if (featuresChanged && reason !== 'writefullEntitlementSynced') {
|
|
|
try {
|
|
|
+ // todo: quota clean-up: simplify once split test isnt needed
|
|
|
+ let hasPremiumAiFeatures
|
|
|
+ const inQuotaSplitTest =
|
|
|
+ await SplitTestHandler.promises.featureFlagEnabledForUser(
|
|
|
+ userId,
|
|
|
+ 'plans-2026-phase-1'
|
|
|
+ )
|
|
|
+ if (inQuotaSplitTest) {
|
|
|
+ hasPremiumAiFeatures =
|
|
|
+ newFeatures.aiUsageQuota === Settings.aiFeatures.unlimitedQuota
|
|
|
+ } else {
|
|
|
+ hasPremiumAiFeatures = Boolean(newFeatures.aiErrorAssistant)
|
|
|
+ }
|
|
|
// update WF with the current feature set for the user
|
|
|
await fetchNothing(
|
|
|
`${Settings.writefull.overleafApiUrl}/api/user/status/update-overleaf-status`,
|
|
|
@@ -100,7 +114,8 @@ async function refreshFeatures(userId, reason) {
|
|
|
},
|
|
|
json: {
|
|
|
userOverleafId: userId,
|
|
|
- hasAiAssist: newFeatures.aiErrorAssistant,
|
|
|
+ // todo: quota clean-up: collab with writefull to rename this, and check if still needed
|
|
|
+ hasAiAssist: hasPremiumAiFeatures,
|
|
|
},
|
|
|
method: 'POST',
|
|
|
}
|
|
|
@@ -192,6 +207,9 @@ async function _getIndividualFeatures(userId) {
|
|
|
featureSets.push(_subscriptionToFeatures(subscription))
|
|
|
}
|
|
|
|
|
|
+ // todo: quota clean-up - remove
|
|
|
+ // if they are in the quota split test, we no longer look at the add-on, since every plan will now have the same quota
|
|
|
+ // standalone plan will receive correct state since their plan will provide the correct quota
|
|
|
featureSets.push(_aiAddOnFeatures(subscription))
|
|
|
return _.reduce(featureSets, FeaturesHelper.mergeFeatures, {})
|
|
|
}
|
|
|
@@ -237,9 +255,14 @@ function _subscriptionToFeatures(subscription) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// todo: quota clean-up: remove post split test
|
|
|
function _aiAddOnFeatures(subscription) {
|
|
|
if (subscription?.addOns?.some(addOn => addOn.addOnCode === AI_ADD_ON_CODE)) {
|
|
|
- return { aiErrorAssistant: true }
|
|
|
+ return {
|
|
|
+ // allow both naming systems to work
|
|
|
+ aiErrorAssistant: true,
|
|
|
+ aiUsageQuota: Settings.aiFeatures.unlimitedQuota,
|
|
|
+ }
|
|
|
} else {
|
|
|
return {}
|
|
|
}
|