mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #20256 from overleaf/jdt-enable-writefull-unset
Differentiate between unset and disabled Writefull GitOrigin-RevId: 3cf8f12ede851dab5a8067bdbcddba6c69870573
This commit is contained in:
parent
edd8a7211f
commit
707790e51e
5 changed files with 95 additions and 56 deletions
|
@ -446,30 +446,6 @@ const _ProjectController = {
|
|||
usedLatex,
|
||||
} = userValues
|
||||
|
||||
// check if a user is not in the writefull-oauth-promotion, in which case they may be part of the auto trial group
|
||||
if (
|
||||
!anonymous &&
|
||||
splitTestAssignments['writefull-oauth-promotion']?.variant === 'default'
|
||||
) {
|
||||
// since we are auto-enrolling users into writefull if they are part of the group, we only want to
|
||||
// auto enroll (set writefull to true) if its the first time they have entered the test
|
||||
// this ensures that they can still turn writefull off (otherwise, we would be setting writefull on every time they access their projects)
|
||||
const { variant, metadata } =
|
||||
await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'writefull-auto-load'
|
||||
)
|
||||
if (variant === 'enabled' && metadata?.isFirstNonDefaultAssignment) {
|
||||
await UserUpdater.promises.updateUser(userId, {
|
||||
$set: {
|
||||
writefull: { enabled: true },
|
||||
},
|
||||
})
|
||||
user.writefull.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
const brandVariation = project?.brandVariationId
|
||||
? await BrandVariationsHandler.promises.getBrandVariationById(
|
||||
project.brandVariationId
|
||||
|
@ -636,16 +612,15 @@ const _ProjectController = {
|
|||
!userIsMemberOfGroupSubscription &&
|
||||
!userHasInstitutionLicence
|
||||
|
||||
let showAiErrorAssistant = false
|
||||
let aiFeaturesAllowed = false
|
||||
if (userId && Features.hasFeature('saas')) {
|
||||
try {
|
||||
// exit early if the user couldnt use ai anyways, since permissions checks are expensive
|
||||
const canUseAiOnProject =
|
||||
user.features?.aiErrorAssistant &&
|
||||
(privilegeLevel === PrivilegeLevels.READ_AND_WRITE ||
|
||||
privilegeLevel === PrivilegeLevels.OWNER)
|
||||
const canEditProject =
|
||||
privilegeLevel === PrivilegeLevels.READ_AND_WRITE ||
|
||||
privilegeLevel === PrivilegeLevels.OWNER
|
||||
|
||||
if (canUseAiOnProject) {
|
||||
if (canEditProject) {
|
||||
// check permissions for user and project owner, to see if they allow AI on the project
|
||||
const permissionsResults = await Modules.promises.hooks.fire(
|
||||
'projectAllowsCapability',
|
||||
|
@ -657,11 +632,34 @@ const _ProjectController = {
|
|||
result => result === true
|
||||
)
|
||||
|
||||
showAiErrorAssistant = aiAllowed
|
||||
aiFeaturesAllowed = aiAllowed
|
||||
}
|
||||
} catch (err) {
|
||||
// still allow users to access project if we cant get their permissions, but disable AI feature
|
||||
showAiErrorAssistant = false
|
||||
aiFeaturesAllowed = false
|
||||
}
|
||||
}
|
||||
|
||||
// check if a user has never tried writefull before (writefull.enabled will be null)
|
||||
// if they previously accepted writefull. user.writefull will be true,
|
||||
// if they explicitly disabled it, user.writefull will be false
|
||||
if (aiFeaturesAllowed && user.writefull?.enabled === null) {
|
||||
// since we are auto-enrolling users into writefull if they are part of the group, we only want to
|
||||
// auto enroll (set writefull to true) if its the first time they have entered the test
|
||||
// this ensures that they can still turn writefull off (otherwise, we would be setting writefull on every time they access their projects)
|
||||
const { variant, metadata } =
|
||||
await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'writefull-auto-load'
|
||||
)
|
||||
if (variant === 'enabled' && metadata?.isFirstNonDefaultAssignment) {
|
||||
await UserUpdater.promises.updateUser(userId, {
|
||||
$set: {
|
||||
writefull: { enabled: true },
|
||||
},
|
||||
})
|
||||
user.writefull.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -693,7 +691,7 @@ const _ProjectController = {
|
|||
features: user.features,
|
||||
refProviders: _.mapValues(user.refProviders, Boolean),
|
||||
writefull: {
|
||||
enabled: Boolean(user.writefull?.enabled),
|
||||
enabled: Boolean(user.writefull?.enabled && aiFeaturesAllowed),
|
||||
},
|
||||
alphaProgram: user.alphaProgram,
|
||||
betaProgram: user.betaProgram,
|
||||
|
@ -741,7 +739,9 @@ const _ProjectController = {
|
|||
debugPdfDetach,
|
||||
showSymbolPalette,
|
||||
symbolPaletteAvailable: Features.hasFeature('symbol-palette'),
|
||||
showAiErrorAssistant,
|
||||
userRestrictions: Array.from(req.userRestrictions || []),
|
||||
showAiErrorAssistant:
|
||||
aiFeaturesAllowed && user.features?.aiErrorAssistant,
|
||||
detachRole,
|
||||
metadata: { viewport: false },
|
||||
showUpgradePrompt,
|
||||
|
|
|
@ -71,13 +71,6 @@ async function settingsPage(req, res) {
|
|||
)
|
||||
}
|
||||
|
||||
// getAssignment sets res.locals, which will pass to the splitTest context
|
||||
await SplitTestHandler.promises.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'writefull-oauth-promotion'
|
||||
)
|
||||
|
||||
let personalAccessTokens
|
||||
try {
|
||||
const results = await Modules.promises.hooks.fire(
|
||||
|
|
|
@ -180,7 +180,7 @@ const UserSchema = new Schema(
|
|||
zotero: Schema.Types.Mixed,
|
||||
},
|
||||
writefull: {
|
||||
enabled: { type: Boolean, default: false },
|
||||
enabled: { type: Boolean, default: null },
|
||||
},
|
||||
alphaProgram: { type: Boolean, default: false }, // experimental features
|
||||
betaProgram: { type: Boolean, default: false },
|
||||
|
|
|
@ -5,7 +5,6 @@ import { useSSOContext, SSOSubscription } from '../context/sso-context'
|
|||
import { SSOLinkingWidget } from './linking/sso-widget'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import { useBroadcastUser } from '@/shared/hooks/user-channel/use-broadcast-user'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import OLNotification from '@/features/ui/components/ol/ol-notification'
|
||||
|
||||
const availableIntegrationLinkingWidgets = importOverleafModules(
|
||||
|
@ -48,19 +47,7 @@ function LinkingSection() {
|
|||
oauth2ServerComponents
|
||||
)
|
||||
|
||||
// currently the only thing that is in the langFeedback section is writefull,
|
||||
// which is behind a split test. we should hide this section if the user is not in the split test
|
||||
// todo: remove split test check, and split test context after gradual rollout is complete
|
||||
const hasWritefullOauthPromotion = useFeatureFlag('writefull-oauth-promotion')
|
||||
|
||||
// even if they arent in the split test, if they have it enabled let them toggle it off
|
||||
const user = getMeta('ol-user')
|
||||
const shouldLoadWritefull =
|
||||
(hasWritefullOauthPromotion || user.writefull?.enabled === true) &&
|
||||
!window.writefull // check if the writefull extension is installed, in which case we dont handle the integration
|
||||
|
||||
const haslangFeedbackLinkingWidgets =
|
||||
langFeedbackLinkingWidgets.length && shouldLoadWritefull
|
||||
const haslangFeedbackLinkingWidgets = langFeedbackLinkingWidgets.length
|
||||
const hasIntegrationLinkingSection =
|
||||
renderSyncSection && allIntegrationLinkingWidgets.length
|
||||
const hasReferencesLinkingSection = referenceLinkingWidgets.length
|
||||
|
|
59
services/web/scripts/split_writefull_disabled_from_unset.js
Normal file
59
services/web/scripts/split_writefull_disabled_from_unset.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
const { db, waitForDb } = require('../app/src/infrastructure/mongodb')
|
||||
const { batchedUpdate } = require('./helpers/batchedUpdate')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
const fs = require('fs')
|
||||
|
||||
const CHUNK_SIZE = 1000
|
||||
|
||||
// Function to chunk the array
|
||||
function chunkArray(array, size) {
|
||||
const result = []
|
||||
for (let i = 0; i < array.length; i += size) {
|
||||
result.push(array.slice(i, i + size))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// search for file of users who already explicitly opted out first
|
||||
const optOutPath = process.argv[2]
|
||||
const optedOutFile = fs.readFileSync(optOutPath, 'utf8')
|
||||
let optedOutList = optedOutFile
|
||||
|
||||
optedOutList = optedOutFile.split('\n').map(id => new ObjectId(id))
|
||||
|
||||
console.log(`preserving opt-outs of ${optedOutList.length} users`)
|
||||
await waitForDb()
|
||||
// update all applicable user models
|
||||
await batchedUpdate(
|
||||
'users',
|
||||
{ 'writefull.enabled': false }, // and is false
|
||||
{ $set: { 'writefull.enabled': null } }
|
||||
)
|
||||
|
||||
const chunks = chunkArray(optedOutList, CHUNK_SIZE)
|
||||
|
||||
// then reset any explicit false back to being false
|
||||
// Iterate over each chunk and perform the query
|
||||
for (const chunkedIds of chunks) {
|
||||
console.log('batch update started')
|
||||
await db.users.updateMany(
|
||||
{ _id: { $in: chunkedIds } },
|
||||
{ $set: { 'writefull.enabled': false } }
|
||||
)
|
||||
console.log('batch completed')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = main
|
||||
|
||||
if (require.main === module) {
|
||||
main()
|
||||
.then(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error({ error })
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue