From 8e5c207f6b44e9d192685df8e61c8d76905bebb4 Mon Sep 17 00:00:00 2001 From: Jimmy Domagala-Tang Date: Thu, 19 Feb 2026 09:09:00 -0500 Subject: [PATCH] Remove Writefull.enabled (#31476) * feat: migrate from aiErrorAssist naming for disabling AI features to aiFeatures.enabled to avoid confusion feat: keep aiErrorAssistant as setting on user object until migration is run * feat: migrate writefull.enabled unset to instead use promotionSet false * feat: remove wf.enabled in favor for aiFeatures.enabled for display, and writefull.promotionSet for determining if we should autoload or autocreate GitOrigin-RevId: 2b7a5b8a430a804f6c9804cc926cb5c057e34df5 --- .../Features/Project/ProjectController.mjs | 39 ++++++------------- .../Project/ProjectListController.mjs | 6 +-- .../src/Features/User/UserPagesController.mjs | 7 +--- services/web/app/src/models/User.mjs | 5 --- services/web/app/views/user/settings.pug | 1 + services/web/scripts/e2e_test_setup.mjs | 4 +- services/web/types/user.ts | 5 --- 7 files changed, 17 insertions(+), 50 deletions(-) diff --git a/services/web/app/src/Features/Project/ProjectController.mjs b/services/web/app/src/Features/Project/ProjectController.mjs index 643938c63b..6e43c54f8a 100644 --- a/services/web/app/src/Features/Project/ProjectController.mjs +++ b/services/web/app/src/Features/Project/ProjectController.mjs @@ -473,7 +473,7 @@ const _ProjectController = { user: (async () => { const user = await User.findById( userId, - 'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiFeatures aiErrorAssistant' + 'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiFeatures' ).exec() // Handle case of deleted user if (!user) { @@ -845,10 +845,7 @@ const _ProjectController = { } const hasPaidSubscription = isPaidSubscription(subscription) - // todo: assist clean-up: remove other case once migration finishes - const aiFeaturesDisabled = - user.aiFeatures?.enabled === false || - user.aiErrorAssistant?.enabled === false // the assistant has been manually disabled by the user + const aiFeaturesDisabled = user.aiFeatures?.enabled === false const addonPrices = isOverleafAssistBundleEnabled && @@ -909,9 +906,7 @@ const _ProjectController = { featureUsage, refProviders: _.mapValues(user.refProviders, Boolean), writefull: { - enabled: Boolean(user.writefull?.enabled && aiFeaturesAllowed), autoCreatedAccount: Boolean(user.writefull?.autoCreatedAccount), - firstAutoLoad: Boolean(user.writefull?.firstAutoLoad), }, alphaProgram: user.alphaProgram, betaProgram: user.betaProgram, @@ -1242,6 +1237,10 @@ const _ProjectController = { aiFeaturesAllowed, userIsMemberOfGroupSubscription ) { + if (!aiFeaturesAllowed) { + return + } + const affiliations = userValues.affiliations const affiliateLookupFailed = affiliations === false @@ -1252,13 +1251,8 @@ const _ProjectController = { affiliation => affiliation.institution?.enterpriseCommons ) - // check if a user has never tried writefull before (writefull.enabled will be null) - // if they previously accepted writefull, or are have been already assigned to a trial, user.writefull will be true, - // if they explicitly disabled it, user.writefull will be false const shouldPushWritefull = - aiFeaturesAllowed && - user.writefull?.enabled === null && - !userIsMemberOfGroupSubscription + user.writefull?.initialized === false && !userIsMemberOfGroupSubscription // we dont have legal approval to push enterprise commons into WF auto-account-create, but we are able to auto-load it into the toolbar const shouldAutoCreateAccount = shouldPushWritefull && !inEnterpriseCommons @@ -1267,28 +1261,16 @@ const _ProjectController = { if (shouldAutoCreateAccount) { await UserUpdater.promises.updateUser(userId, { $set: { - writefull: { - enabled: true, - initialized: true, - autoCreatedAccount: true, - }, + writefull: { autoCreatedAccount: true, initialized: true }, }, }) - user.writefull.enabled = true - user.writefull.initialized = true user.writefull.autoCreatedAccount = true } else if (shouldAutoLoad) { await UserUpdater.promises.updateUser(userId, { $set: { - writefull: { - enabled: true, - initialized: true, - autoCreatedAccount: false, - }, + writefull: { autoCreatedAccount: false, initialized: true }, }, }) - user.writefull.enabled = true - user.writefull.initialized = true user.writefull.autoCreatedAccount = false } }, @@ -1316,6 +1298,9 @@ const defaultSettingsForAnonymousUser = userId => ({ alphaProgram: false, betaProgram: false, writefull: { + initialized: true, + }, + aiFeatures: { enabled: false, }, }) diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index a006f7e050..94355cc274 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -918,11 +918,7 @@ async function _userHasAIAssist(user) { // It does NOT determine if the user has AI Assist enabled async function _canUseAIAssist(user) { // Check if the assistant has been manually disabled by the user - // todo: assist clean-up: remove other case once migration finishes - if ( - user.aiErrorAssistant?.enabled === false || - user.aiFeatures?.enabled === false - ) { + if (user.aiFeatures?.enabled === false) { return false } diff --git a/services/web/app/src/Features/User/UserPagesController.mjs b/services/web/app/src/Features/User/UserPagesController.mjs index 6a69bc5057..ba308bb032 100644 --- a/services/web/app/src/Features/User/UserPagesController.mjs +++ b/services/web/app/src/Features/User/UserPagesController.mjs @@ -144,13 +144,8 @@ async function settingsPage(req, res) { zotero: Boolean(user.refProviders?.zotero), papers: Boolean(user.refProviders?.papers), }, - writefull: { - enabled: Boolean(user.writefull?.enabled), - }, - aiFeatures: { - enabled: Boolean(user.aiFeatures?.enabled), - }, }, + showAiFeatures: Boolean(user.aiFeatures?.enabled), labsExperiments: user.labsExperiments ?? [], hasPassword: !!user.hashedPassword, shouldAllowEditingDetails, diff --git a/services/web/app/src/models/User.mjs b/services/web/app/src/models/User.mjs index bb957b8d57..454d378622 100644 --- a/services/web/app/src/models/User.mjs +++ b/services/web/app/src/models/User.mjs @@ -193,7 +193,6 @@ export const UserSchema = new Schema( papers: Schema.Types.Mixed, }, writefull: { - enabled: { type: Boolean, default: null }, // whether we have attached an autocreated account or autoloading for the user initialized: { type: Boolean, default: false }, autoCreatedAccount: { type: Boolean, default: false }, @@ -203,10 +202,6 @@ export const UserSchema = new Schema( aiFeatures: { enabled: { type: Boolean, default: true }, }, - // todo: assist clean-up: remove this once migration is finished - aiErrorAssistant: { - enabled: { type: Boolean, default: true }, - }, alphaProgram: { type: Boolean, default: false }, // experimental features betaProgram: { type: Boolean, default: false }, labsProgram: { type: Boolean, default: false }, diff --git a/services/web/app/views/user/settings.pug b/services/web/app/views/user/settings.pug index 45d21c7572..d690f0b4e1 100644 --- a/services/web/app/views/user/settings.pug +++ b/services/web/app/views/user/settings.pug @@ -37,6 +37,7 @@ block append meta content=externalAuthenticationSystemUsed() ) meta(name='ol-user' data-type='json' content=user) + meta(name='ol-showAiFeatures' data-type='boolean' content=showAiFeatures) meta(name='ol-labsExperiments' data-type='json' content=labsExperiments) meta(name='ol-dropbox' data-type='json' content=dropbox) meta(name='ol-github' data-type='json' content=github) diff --git a/services/web/scripts/e2e_test_setup.mjs b/services/web/scripts/e2e_test_setup.mjs index 071f044f76..9c4f5254f2 100644 --- a/services/web/scripts/e2e_test_setup.mjs +++ b/services/web/scripts/e2e_test_setup.mjs @@ -38,8 +38,8 @@ async function createUser(email) { // Override features. features, featuresOverrides: [{ features }], - // disable Writefull - 'writefull.enabled': false, + // disable AI features + 'aiFeatures.enabled': false, }, } ) diff --git a/services/web/types/user.ts b/services/web/types/user.ts index 2fce1ce46b..d039b95f83 100644 --- a/services/web/types/user.ts +++ b/services/web/types/user.ts @@ -49,14 +49,9 @@ export type User = { features?: Features refProviders?: RefProviders writefull?: { - enabled: boolean autoCreatedAccount: boolean - firstAutoLoad: boolean premiumSource: string } - aiErrorAssistant?: { - enabled: boolean - } featureUsage?: FeatureUsage planCode?: string planName?: string