diff --git a/packages/backend/src/models/user.js b/packages/backend/src/models/user.js index f1e88572..99314e07 100644 --- a/packages/backend/src/models/user.js +++ b/packages/backend/src/models/user.js @@ -607,7 +607,35 @@ class User extends Base { this.email = this.email.toLowerCase(); } } - g; + + async createUsageData() { + if (appConfig.isCloud) { + return await this.$relatedQuery('usageData').insertAndFetch({ + userId: this.id, + consumedTaskCount: 0, + nextResetAt: DateTime.now().plus({ days: 30 }).toISODate(), + }); + } + } + + async omitEnterprisePermissionsWithoutValidLicense() { + if (await hasValidLicense()) { + return this; + } + + if (Array.isArray(this.permissions)) { + this.permissions = this.permissions.filter((permission) => { + const restrictedSubjects = [ + 'App', + 'Role', + 'SamlAuthProvider', + 'Config', + ]; + + return !restrictedSubjects.includes(permission.subject); + }); + } + } async $beforeInsert(queryContext) { await super.$beforeInsert(queryContext); @@ -631,32 +659,11 @@ class User extends Base { async $afterInsert(queryContext) { await super.$afterInsert(queryContext); - if (appConfig.isCloud) { - await this.$relatedQuery('usageData').insert({ - userId: this.id, - consumedTaskCount: 0, - nextResetAt: DateTime.now().plus({ days: 30 }).toISODate(), - }); - } + await this.createUsageData(); } async $afterFind() { - if (await hasValidLicense()) return this; - - if (Array.isArray(this.permissions)) { - this.permissions = this.permissions.filter((permission) => { - const restrictedSubjects = [ - 'App', - 'Role', - 'SamlAuthProvider', - 'Config', - ]; - - return !restrictedSubjects.includes(permission.subject); - }); - } - - return this; + await this.omitEnterprisePermissionsWithoutValidLicense(); } } diff --git a/packages/backend/src/models/user.test.js b/packages/backend/src/models/user.test.js index 50ed156f..14d0f015 100644 --- a/packages/backend/src/models/user.test.js +++ b/packages/backend/src/models/user.test.js @@ -1,6 +1,7 @@ import { describe, it, expect, vi } from 'vitest'; import { DateTime, Duration } from 'luxon'; import appConfig from '../config/app.js'; +import * as licenseModule from '../helpers/license.ee.js'; import Base from './base.js'; import AccessToken from './access-token.js'; import Config from './config.js'; @@ -1352,4 +1353,181 @@ describe('User model', () => { expect(await user.login('new-password')).toBe(true); }); }); + + describe('createUsageData', () => { + it('should create usage data if Automatisch is a cloud installation', async () => { + vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true); + + const user = await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + }); + + const usageData = await user.createUsageData(); + const currentUsageData = await user.$relatedQuery('currentUsageData'); + + expect(usageData).toStrictEqual(currentUsageData); + }); + + it('should not create usage data if Automatisch is not a cloud installation', async () => { + vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(false); + + const user = await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + }); + + const usageData = await user.createUsageData(); + + expect(usageData).toBe(undefined); + }); + }); + + describe('omitEnterprisePermissionsWithoutValidLicense', () => { + it('should return user as-is with valid license', async () => { + const userRole = await createRole({ name: 'User' }); + const user = await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + roleId: userRole.id, + }); + + const readFlowPermission = await createPermission({ + roleId: userRole.id, + subject: 'Flow', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'App', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'Role', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'Config', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'SamlAuthProvider', + action: 'read', + conditions: [], + }); + + const userWithRoleAndPermissions = await user + .$query() + .withGraphFetched({ role: true, permissions: true }); + + expect(userWithRoleAndPermissions.permissions).toStrictEqual([ + readFlowPermission, + ]); + }); + + it('should omit enterprise permissions without valid license', async () => { + vi.spyOn(licenseModule, 'hasValidLicense').mockResolvedValue(false); + + const userRole = await createRole({ name: 'User' }); + const user = await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + roleId: userRole.id, + }); + + const readFlowPermission = await createPermission({ + roleId: userRole.id, + subject: 'Flow', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'App', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'Role', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'Config', + action: 'read', + conditions: [], + }); + + await createPermission({ + roleId: userRole.id, + subject: 'SamlAuthProvider', + action: 'read', + conditions: [], + }); + + const userWithRoleAndPermissions = await user + .$query() + .withGraphFetched({ role: true, permissions: true }); + + expect(userWithRoleAndPermissions.permissions).toStrictEqual([ + readFlowPermission, + ]); + }); + }); + + describe('$afterInsert', () => { + it('should call super.$afterInsert', async () => { + const superAfterInsertSpy = vi.spyOn(User.prototype, '$afterInsert'); + + await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + }); + + expect(superAfterInsertSpy).toHaveBeenCalledOnce(); + }); + + it('should call createUsageData', async () => { + const createUsageDataSpy = vi.spyOn(User.prototype, 'createUsageData'); + + await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + }); + + expect(createUsageDataSpy).toHaveBeenCalledOnce(); + }); + }); + + it('$afterFind should invoke omitEnterprisePermissionsWithoutValidLicense method', async () => { + const omitEnterprisePermissionsWithoutValidLicenseSpy = vi.spyOn( + User.prototype, + 'omitEnterprisePermissionsWithoutValidLicense' + ); + + await createUser({ + fullName: 'Sample user', + email: 'user@automatisch.io', + }); + + expect( + omitEnterprisePermissionsWithoutValidLicenseSpy + ).toHaveBeenCalledOnce(); + }); });