mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
[web] Disabled AI state for project collaborators (#34256)
* [web] Disabled AI state for project collaborators Displays a disabled state, along with an informative tooltip in Editor AI controls. GitOrigin-RevId: a749cd25d54f6ef3d7bf4276343400894bc193a4
This commit is contained in:
@@ -250,6 +250,12 @@ describe('ProjectController', function () {
|
||||
}),
|
||||
}
|
||||
|
||||
ctx.PermissionsManager = {
|
||||
promises: {
|
||||
checkUserPermissions: sinon.stub().resolves(false),
|
||||
},
|
||||
}
|
||||
|
||||
vi.doMock('mongodb-legacy', () => ({
|
||||
default: { ObjectId },
|
||||
}))
|
||||
@@ -515,6 +521,13 @@ describe('ProjectController', function () {
|
||||
})
|
||||
)
|
||||
|
||||
vi.doMock(
|
||||
'../../../../app/src/Features/Authorization/PermissionsManager',
|
||||
() => ({
|
||||
default: ctx.PermissionsManager,
|
||||
})
|
||||
)
|
||||
|
||||
ctx.ProjectController = (await import(MODULE_PATH)).default
|
||||
|
||||
ctx.projectName = '£12321jkj9ujkljds'
|
||||
@@ -1510,6 +1523,230 @@ describe('ProjectController', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('AI features availability', function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.Features.hasFeature.withArgs('saas').returns(true)
|
||||
ctx.Modules.promises.hooks.fire = sinon.stub().resolves([[true]])
|
||||
ctx.settings.localizedAddOnsPricing = {
|
||||
USD: {
|
||||
assistant: {
|
||||
annual: 60,
|
||||
monthly: 5,
|
||||
annualDividedByTwelve: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to true when the user has the use-ai permission', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(true)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false when the user lacks the use-ai permission', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(false)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false when the user has disabled ai features', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
ctx.user.aiFeatures = { enabled: false }
|
||||
ctx.UserModel.findById.returns({
|
||||
exec: sinon.stub().resolves(ctx.user),
|
||||
})
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false when the permission check throws', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.rejects(
|
||||
new Error('permission check failed')
|
||||
)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false when the project owner permission check throws', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
ctx.PermissionsManager.promises.checkUserPermissions
|
||||
.onSecondCall()
|
||||
.rejects(new Error('permission check failed'))
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false when the user can use ai but the project disallows it', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.callsFake(
|
||||
subject => Promise.resolve(typeof subject !== 'string')
|
||||
)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeaturesDisabled to false when the user can use ai and the project allows it', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
ctx.Modules.promises.hooks.fire = sinon.stub().resolves([true])
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeaturesDisabled to false when the user lacks the use-ai permission', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(false)
|
||||
ctx.Modules.promises.hooks.fire = sinon.stub().resolves([[false]])
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeaturesDisabled to false when the user has disabled ai features', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
ctx.Modules.promises.hooks.fire = sinon.stub().resolves([[false]])
|
||||
ctx.user.aiFeatures = { enabled: false }
|
||||
ctx.UserModel.findById.returns({
|
||||
exec: sinon.stub().resolves(ctx.user),
|
||||
})
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("when the 'ai-disabled-collaborators' variant is enabled", function () {
|
||||
beforeEach(function (ctx) {
|
||||
ctx.SplitTestHandler.promises.getAssignment
|
||||
.withArgs(ctx.req, ctx.res, 'ai-disabled-collaborators')
|
||||
.resolves({ variant: 'enabled' })
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to true and showAiFeaturesDisabled to true when the user can use ai but the project disallows it', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.callsFake(
|
||||
subject => Promise.resolve(typeof subject !== 'string')
|
||||
)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(true)
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(true)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to true and showAiFeaturesDisabled to false when the user can use ai and the project allows it', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(true)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(true)
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false and showAiFeaturesDisabled to false when the user lacks the use-ai permission', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.resolves(false)
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set showAiFeatures to false and showAiFeaturesDisabled to false when the user has disabled ai features', async function (ctx) {
|
||||
ctx.PermissionsManager.promises.checkUserPermissions.callsFake(
|
||||
subject => Promise.resolve(typeof subject !== 'string')
|
||||
)
|
||||
ctx.user.aiFeatures = { enabled: false }
|
||||
ctx.UserModel.findById.returns({
|
||||
exec: sinon.stub().resolves(ctx.user),
|
||||
})
|
||||
await new Promise((resolve, reject) => {
|
||||
ctx.res.render = (pageName, opts) => {
|
||||
expect(opts.showAiFeatures).to.equal(false)
|
||||
expect(opts.showAiFeaturesDisabled).to.equal(false)
|
||||
resolve()
|
||||
}
|
||||
ctx.ProjectController.loadEditor(ctx.req, ctx.res, err => {
|
||||
if (err) reject(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('userProjectsJson', function () {
|
||||
|
||||
Reference in New Issue
Block a user