diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 60d964e532..4c4ed17fb2 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -423,6 +423,8 @@ async function projectListPage(req, res, next) { // customer.io: Premium nudge experiment // Only do customer-io-trial-conversion assignment for users not in India/China and not in group/commons let customerIoEnabled = false + const aiBlocked = !(await _canUseAIAssist(user)) + const hasAiAssist = await _userHasAIAssist(user) if (!userIsMemberOfGroupSubscription && !inEnterpriseCommons) { try { const ip = req.ip @@ -487,6 +489,8 @@ async function projectListPage(req, res, next) { userRestrictions: Array.from(req.userRestrictions || []), customerIoEnabled, showAiAssistNotification, + aiBlocked, + hasAiAssist, }) } @@ -771,6 +775,35 @@ function _hasActiveFilter(filters) { ) } +async function _userHasAIAssist(user) { + // Check if the user has AI Assist enabled via Overleaf + if (user.features?.aiErrorAssistant) { + return true + } + // Check if the user has AI Assist enabled via Writefull + const { isPremium: hasAiAssistViaWritefull } = + await UserGetter.promises.getWritefullData(user._id) + if (hasAiAssistViaWritefull) { + return true + } + return false +} + +// Determines if user is able to enable AI assist +// based on their permissions and settings +// 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 + if (user.aiErrorAssistant?.enabled === false) { + return false + } + + // Check if the user can use AI features (policy check) + return await PermissionsManager.promises.checkUserPermissions(user, [ + 'use-ai', + ]) +} + async function _showAiAssistNotification(user) { // Check if the assistant has been manually disabled by the user if (user.aiErrorAssistant?.enabled === false) { @@ -794,18 +827,8 @@ async function _showAiAssistNotification(user) { return false } - // Check if the user already has AI Assist via Overleaf - if (user.features?.aiErrorAssistant) { - return false - } - // Check if the user already has AI Assist via Writefull - const { isPremium: hasAiAssistViaWritefull } = - await UserGetter.promises.getWritefullData(user._id) - if (hasAiAssistViaWritefull) { - return false - } - - return true + const userHasAiAssist = await _userHasAIAssist(user) + return !userHasAiAssist } export default { diff --git a/services/web/app/views/_customer_io.pug b/services/web/app/views/_customer_io.pug index 781dfaab13..61b4dc9f1d 100644 --- a/services/web/app/views/_customer_io.pug +++ b/services/web/app/views/_customer_io.pug @@ -1,11 +1,22 @@ if(customerIoEnabled && ExposedSettings.cioWriteKey && ExposedSettings.cioSiteId) - script(type="text/javascript", id="cio-loader", nonce=scriptNonce, data-best-subscription=(usersBestSubscription && usersBestSubscription.type), data-cio-write-key=ExposedSettings.cioWriteKey, data-cio-site-id=ExposedSettings.cioSiteId, data-session-analytics-id=getSessionAnalyticsId(), data-user-id=getLoggedInUserId()). + - + function boolAttr(value) { + return value !== undefined ? String(value) : null; + } + script(type="text/javascript", id="cio-loader", nonce=scriptNonce, data-best-subscription=(usersBestSubscription && usersBestSubscription.type), data-ai-blocked=boolAttr(aiBlocked), data-has-ai-assist=boolAttr(hasAiAssist), data-cio-write-key=ExposedSettings.cioWriteKey, data-cio-site-id=ExposedSettings.cioSiteId, data-session-analytics-id=getSessionAnalyticsId(), data-user-id=getLoggedInUserId()). + + function parseBool(value) { + return value === 'true' ? true : value === 'false' ? false : undefined; + } + var cioSettings = document.querySelector('#cio-loader').dataset; var analyticsId = cioSettings.sessionAnalyticsId; var siteId = cioSettings.cioSiteId; var writeKey = cioSettings.cioWriteKey; var userId = cioSettings.userId; - var usersBestSubscription = cioSettings.bestSubscription + var usersBestSubscription = cioSettings.bestSubscription; + var aiBlocked = parseBool(cioSettings.aiBlocked); + var hasAiAssist = parseBool(cioSettings.hasAiAssist); !function(){var i="cioanalytics", analytics=(window[i]=window[i]||[]);if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e