mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: User audit events (create, update, delete) should include rootRole. (#5399)
Audit events for USER_CREATE, USER_UPDATE and USER_DELETE did not include the users rootRole.  --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
This commit is contained in:
		
							parent
							
								
									47e214d96f
								
							
						
					
					
						commit
						f00eac0881
					
				@ -12,7 +12,7 @@ import {
 | 
				
			|||||||
    IUserRole,
 | 
					    IUserRole,
 | 
				
			||||||
    IUserWithProjectRoles,
 | 
					    IUserWithProjectRoles,
 | 
				
			||||||
} from '../types/stores/access-store';
 | 
					} from '../types/stores/access-store';
 | 
				
			||||||
import { IPermission, IUserAccessOverview } from '../types/model';
 | 
					import { IPermission, IUserAccessOverview, RoleType } from '../types/model';
 | 
				
			||||||
import NotFoundError from '../error/notfound-error';
 | 
					import NotFoundError from '../error/notfound-error';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    ENVIRONMENT_PERMISSION_TYPE,
 | 
					    ENVIRONMENT_PERMISSION_TYPE,
 | 
				
			||||||
@ -360,6 +360,7 @@ export class AccessStore implements IAccessStore {
 | 
				
			|||||||
            .andWhere('ru.project', projectId);
 | 
					            .andWhere('ru.project', projectId);
 | 
				
			||||||
        return rows.map((r) => ({
 | 
					        return rows.map((r) => ({
 | 
				
			||||||
            userId: r.user_id,
 | 
					            userId: r.user_id,
 | 
				
			||||||
 | 
					            roleId,
 | 
				
			||||||
            addedAt: r.created_at,
 | 
					            addedAt: r.created_at,
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -400,6 +401,16 @@ export class AccessStore implements IAccessStore {
 | 
				
			|||||||
            .where('ru.user_id', '=', userId);
 | 
					            .where('ru.user_id', '=', userId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async getRootRoleForUser(userId: number): Promise<IRole | undefined> {
 | 
				
			||||||
 | 
					        return this.db
 | 
				
			||||||
 | 
					            .select(['id', 'name', 'type', 'description'])
 | 
				
			||||||
 | 
					            .from<IRole[]>(T.ROLES)
 | 
				
			||||||
 | 
					            .innerJoin(`${T.ROLE_USER} as ru`, 'ru.role_id', 'id')
 | 
				
			||||||
 | 
					            .where('ru.user_id', '=', userId)
 | 
				
			||||||
 | 
					            .andWhere('type', '=', RoleType.ROOT)
 | 
				
			||||||
 | 
					            .first();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getUserIdsForRole(roleId: number): Promise<number[]> {
 | 
					    async getUserIdsForRole(roleId: number): Promise<number[]> {
 | 
				
			||||||
        const rows = await this.db
 | 
					        const rows = await this.db
 | 
				
			||||||
            .select(['user_id'])
 | 
					            .select(['user_id'])
 | 
				
			||||||
 | 
				
			|||||||
@ -170,8 +170,7 @@ class UserController extends Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const projects = await this.projectService.getProjectsByUser(user.id);
 | 
					        const projects = await this.projectService.getProjectsByUser(user.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const roles = await this.accessService.getUserRootRoles(user.id);
 | 
					        const rootRole = await this.accessService.getRootRoleForUser(user.id);
 | 
				
			||||||
        const { project, ...rootRole } = roles[0];
 | 
					 | 
				
			||||||
        const responseData: ProfileSchema = {
 | 
					        const responseData: ProfileSchema = {
 | 
				
			||||||
            projects,
 | 
					            projects,
 | 
				
			||||||
            rootRole,
 | 
					            rootRole,
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,13 @@ describe('Public Signup API', () => {
 | 
				
			|||||||
            ...stores.accessStore,
 | 
					            ...stores.accessStore,
 | 
				
			||||||
            addUserToRole: jest.fn(),
 | 
					            addUserToRole: jest.fn(),
 | 
				
			||||||
            removeRolesOfTypeForUser: jest.fn(),
 | 
					            removeRolesOfTypeForUser: jest.fn(),
 | 
				
			||||||
 | 
					            getRolesForUserId: () => Promise.resolve([]),
 | 
				
			||||||
 | 
					            getRootRoleForUser: () =>
 | 
				
			||||||
 | 
					                Promise.resolve({
 | 
				
			||||||
 | 
					                    id: -1,
 | 
				
			||||||
 | 
					                    name: RoleName.VIEWER,
 | 
				
			||||||
 | 
					                    type: RoleType.ROOT,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const services = createServices(stores, config);
 | 
					        const services = createServices(stores, config);
 | 
				
			||||||
 | 
				
			|||||||
@ -190,9 +190,8 @@ test('user with custom root role should get a user root role', async () => {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    await accessService.setUserRootRole(user.id, customRootRole.id);
 | 
					    await accessService.setUserRootRole(user.id, customRootRole.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const roles = await accessService.getUserRootRoles(user.id);
 | 
					    const role = await accessService.getRootRoleForUser(user.id);
 | 
				
			||||||
    expect(roles).toHaveLength(1);
 | 
					    expect(role.name).toBe('custom-root-role');
 | 
				
			||||||
    expect(roles[0].name).toBe('custom-root-role');
 | 
					 | 
				
			||||||
    const events = await eventStore.getEvents();
 | 
					    const events = await eventStore.getEvents();
 | 
				
			||||||
    expect(events).toHaveLength(1);
 | 
					    expect(events).toHaveLength(1);
 | 
				
			||||||
    expect(events[0]).toEqual({
 | 
					    expect(events[0]).toEqual({
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,6 @@ import {
 | 
				
			|||||||
    IRole,
 | 
					    IRole,
 | 
				
			||||||
    IRoleDescriptor,
 | 
					    IRoleDescriptor,
 | 
				
			||||||
    IRoleWithPermissions,
 | 
					    IRoleWithPermissions,
 | 
				
			||||||
    IRoleWithProject,
 | 
					 | 
				
			||||||
    IUserPermission,
 | 
					    IUserPermission,
 | 
				
			||||||
    IUserRole,
 | 
					    IUserRole,
 | 
				
			||||||
    IUserWithProjectRoles,
 | 
					    IUserWithProjectRoles,
 | 
				
			||||||
@ -362,9 +361,13 @@ export class AccessService {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getUserRootRoles(userId: number): Promise<IRoleWithProject[]> {
 | 
					    async getRootRoleForUser(userId: number): Promise<IRole> {
 | 
				
			||||||
        const userRoles = await this.store.getRolesForUserId(userId);
 | 
					        const rootRole = await this.store.getRootRoleForUser(userId);
 | 
				
			||||||
        return userRoles.filter(({ type }) => ROOT_ROLE_TYPES.includes(type));
 | 
					        if (!rootRole) {
 | 
				
			||||||
 | 
					            const defaultRole = await this.getPredefinedRole(RoleName.VIEWER);
 | 
				
			||||||
 | 
					            return defaultRole;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return rootRole;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async removeUserFromRole(
 | 
					    async removeUserFromRole(
 | 
				
			||||||
@ -602,9 +605,20 @@ export class AccessService {
 | 
				
			|||||||
        return role;
 | 
					        return role;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getRootRole(roleName: RoleName): Promise<IRole | undefined> {
 | 
					    /*
 | 
				
			||||||
        const roles = await this.roleStore.getRootRoles();
 | 
					        This method is intended to give a predicable way to fetch 
 | 
				
			||||||
        return roles.find((r) => r.name === roleName);
 | 
					        pre-defined roles defined in the RoleName enum. This method
 | 
				
			||||||
 | 
					        should not be used to fetch custom root or project roles. 
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    async getPredefinedRole(roleName: RoleName): Promise<IRole> {
 | 
				
			||||||
 | 
					        const roles = await this.roleStore.getRoles();
 | 
				
			||||||
 | 
					        const role = roles.find((r) => r.name === roleName);
 | 
				
			||||||
 | 
					        if (!role) {
 | 
				
			||||||
 | 
					            throw new BadDataError(
 | 
				
			||||||
 | 
					                `Could not find pre-defined role with name ${RoleName}`,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return role;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getAllRoles(): Promise<ICustomRole[]> {
 | 
					    async getAllRoles(): Promise<ICustomRole[]> {
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ export class AccountService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    async getAll(): Promise<IUserWithRole[]> {
 | 
					    async getAll(): Promise<IUserWithRole[]> {
 | 
				
			||||||
        const accounts = await this.store.getAll();
 | 
					        const accounts = await this.store.getAll();
 | 
				
			||||||
        const defaultRole = await this.accessService.getRootRole(
 | 
					        const defaultRole = await this.accessService.getPredefinedRole(
 | 
				
			||||||
            RoleName.VIEWER,
 | 
					            RoleName.VIEWER,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const userRoles = await this.accessService.getRootRoleForAllUsers();
 | 
					        const userRoles = await this.accessService.getRootRoleForAllUsers();
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ import Joi from 'joi';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { URL } from 'url';
 | 
					import { URL } from 'url';
 | 
				
			||||||
import { Logger } from '../logger';
 | 
					import { Logger } from '../logger';
 | 
				
			||||||
import User, { IUser } from '../types/user';
 | 
					import User, { IUser, IUserWithRootRole } from '../types/user';
 | 
				
			||||||
import isEmail from '../util/is-email';
 | 
					import isEmail from '../util/is-email';
 | 
				
			||||||
import { AccessService } from './access-service';
 | 
					import { AccessService } from './access-service';
 | 
				
			||||||
import ResetTokenService from './reset-token-service';
 | 
					import ResetTokenService from './reset-token-service';
 | 
				
			||||||
@ -16,7 +16,14 @@ import { IAuthOption, IUnleashConfig } from '../types/option';
 | 
				
			|||||||
import SessionService from './session-service';
 | 
					import SessionService from './session-service';
 | 
				
			||||||
import { IUnleashStores } from '../types/stores';
 | 
					import { IUnleashStores } from '../types/stores';
 | 
				
			||||||
import PasswordUndefinedError from '../error/password-undefined';
 | 
					import PasswordUndefinedError from '../error/password-undefined';
 | 
				
			||||||
import { USER_UPDATED, USER_CREATED, USER_DELETED } from '../types/events';
 | 
					import {
 | 
				
			||||||
 | 
					    USER_UPDATED,
 | 
				
			||||||
 | 
					    USER_CREATED,
 | 
				
			||||||
 | 
					    USER_DELETED,
 | 
				
			||||||
 | 
					    UserCreatedEvent,
 | 
				
			||||||
 | 
					    UserUpdatedEvent,
 | 
				
			||||||
 | 
					    UserDeletedEvent,
 | 
				
			||||||
 | 
					} from '../types/events';
 | 
				
			||||||
import { IUserStore } from '../types/stores/user-store';
 | 
					import { IUserStore } from '../types/stores/user-store';
 | 
				
			||||||
import { RoleName } from '../types/model';
 | 
					import { RoleName } from '../types/model';
 | 
				
			||||||
import SettingService from './setting-service';
 | 
					import SettingService from './setting-service';
 | 
				
			||||||
@ -53,10 +60,6 @@ export interface ILoginUserRequest {
 | 
				
			|||||||
    autoCreate?: boolean;
 | 
					    autoCreate?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IUserWithRole extends IUser {
 | 
					 | 
				
			||||||
    rootRole: number;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const saltRounds = 10;
 | 
					const saltRounds = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserService {
 | 
					class UserService {
 | 
				
			||||||
@ -173,9 +176,9 @@ class UserService {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getAll(): Promise<IUserWithRole[]> {
 | 
					    async getAll(): Promise<IUserWithRootRole[]> {
 | 
				
			||||||
        const users = await this.store.getAll();
 | 
					        const users = await this.store.getAll();
 | 
				
			||||||
        const defaultRole = await this.accessService.getRootRole(
 | 
					        const defaultRole = await this.accessService.getPredefinedRole(
 | 
				
			||||||
            RoleName.VIEWER,
 | 
					            RoleName.VIEWER,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const userRoles = await this.accessService.getRootRoleForAllUsers();
 | 
					        const userRoles = await this.accessService.getRootRoleForAllUsers();
 | 
				
			||||||
@ -187,14 +190,10 @@ class UserService {
 | 
				
			|||||||
        return usersWithRootRole;
 | 
					        return usersWithRootRole;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getUser(id: number): Promise<IUserWithRole> {
 | 
					    async getUser(id: number): Promise<IUserWithRootRole> {
 | 
				
			||||||
        const roles = await this.accessService.getUserRootRoles(id);
 | 
					 | 
				
			||||||
        const defaultRole = await this.accessService.getRootRole(
 | 
					 | 
				
			||||||
            RoleName.VIEWER,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        const roleId = roles.length > 0 ? roles[0].id : defaultRole.id;
 | 
					 | 
				
			||||||
        const user = await this.store.get(id);
 | 
					        const user = await this.store.get(id);
 | 
				
			||||||
        return { ...user, rootRole: roleId };
 | 
					        const rootRole = await this.accessService.getRootRoleForUser(id);
 | 
				
			||||||
 | 
					        return { ...user, rootRole: rootRole.id };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async search(query: string): Promise<IUser[]> {
 | 
					    async search(query: string): Promise<IUser[]> {
 | 
				
			||||||
@ -208,7 +207,7 @@ class UserService {
 | 
				
			|||||||
    async createUser(
 | 
					    async createUser(
 | 
				
			||||||
        { username, email, name, password, rootRole }: ICreateUser,
 | 
					        { username, email, name, password, rootRole }: ICreateUser,
 | 
				
			||||||
        updatedBy?: IUser,
 | 
					        updatedBy?: IUser,
 | 
				
			||||||
    ): Promise<IUser> {
 | 
					    ): Promise<IUserWithRootRole> {
 | 
				
			||||||
        if (!username && !email) {
 | 
					        if (!username && !email) {
 | 
				
			||||||
            throw new BadDataError('You must specify username or email');
 | 
					            throw new BadDataError('You must specify username or email');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -235,36 +234,27 @@ class UserService {
 | 
				
			|||||||
            await this.store.setPasswordHash(user.id, passwordHash);
 | 
					            await this.store.setPasswordHash(user.id, passwordHash);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.eventService.storeEvent({
 | 
					        const userCreated = await this.getUser(user.id);
 | 
				
			||||||
            type: USER_CREATED,
 | 
					 | 
				
			||||||
            createdBy: this.getCreatedBy(updatedBy),
 | 
					 | 
				
			||||||
            data: this.mapUserToData(user),
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return user;
 | 
					        await this.eventService.storeEvent(
 | 
				
			||||||
 | 
					            new UserCreatedEvent({
 | 
				
			||||||
 | 
					                createdBy: this.getCreatedBy(updatedBy),
 | 
				
			||||||
 | 
					                userCreated,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return userCreated;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private getCreatedBy(updatedBy: IUser = systemUser) {
 | 
					    private getCreatedBy(updatedBy: IUser = systemUser) {
 | 
				
			||||||
        return updatedBy.username || updatedBy.email;
 | 
					        return updatedBy.username || updatedBy.email;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private mapUserToData(user?: IUser): any {
 | 
					 | 
				
			||||||
        if (!user) {
 | 
					 | 
				
			||||||
            return undefined;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            id: user.id,
 | 
					 | 
				
			||||||
            name: user.name,
 | 
					 | 
				
			||||||
            username: user.username,
 | 
					 | 
				
			||||||
            email: user.email,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async updateUser(
 | 
					    async updateUser(
 | 
				
			||||||
        { id, name, email, rootRole }: IUpdateUser,
 | 
					        { id, name, email, rootRole }: IUpdateUser,
 | 
				
			||||||
        updatedBy?: IUser,
 | 
					        updatedBy?: IUser,
 | 
				
			||||||
    ): Promise<IUser> {
 | 
					    ): Promise<IUserWithRootRole> {
 | 
				
			||||||
        const preUser = await this.store.get(id);
 | 
					        const preUser = await this.getUser(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (email) {
 | 
					        if (email) {
 | 
				
			||||||
            Joi.assert(email, Joi.string().email(), 'Email');
 | 
					            Joi.assert(email, Joi.string().email(), 'Email');
 | 
				
			||||||
@ -284,28 +274,32 @@ class UserService {
 | 
				
			|||||||
            ? await this.store.update(id, payload)
 | 
					            ? await this.store.update(id, payload)
 | 
				
			||||||
            : preUser;
 | 
					            : preUser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.eventService.storeEvent({
 | 
					        const storedUser = await this.getUser(user.id);
 | 
				
			||||||
            type: USER_UPDATED,
 | 
					 | 
				
			||||||
            createdBy: this.getCreatedBy(updatedBy),
 | 
					 | 
				
			||||||
            data: this.mapUserToData(user),
 | 
					 | 
				
			||||||
            preData: this.mapUserToData(preUser),
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return user;
 | 
					        await this.eventService.storeEvent(
 | 
				
			||||||
 | 
					            new UserUpdatedEvent({
 | 
				
			||||||
 | 
					                createdBy: this.getCreatedBy(updatedBy),
 | 
				
			||||||
 | 
					                preUser: preUser,
 | 
				
			||||||
 | 
					                postUser: storedUser,
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return storedUser;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async deleteUser(userId: number, updatedBy?: IUser): Promise<void> {
 | 
					    async deleteUser(userId: number, updatedBy?: IUser): Promise<void> {
 | 
				
			||||||
        const user = await this.store.get(userId);
 | 
					        const user = await this.getUser(userId);
 | 
				
			||||||
        await this.accessService.wipeUserPermissions(userId);
 | 
					        await this.accessService.wipeUserPermissions(userId);
 | 
				
			||||||
        await this.sessionService.deleteSessionsForUser(userId);
 | 
					        await this.sessionService.deleteSessionsForUser(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.store.delete(userId);
 | 
					        await this.store.delete(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.eventService.storeEvent({
 | 
					        await this.eventService.storeEvent(
 | 
				
			||||||
            type: USER_DELETED,
 | 
					            new UserDeletedEvent({
 | 
				
			||||||
            createdBy: this.getCreatedBy(updatedBy),
 | 
					                createdBy: this.getCreatedBy(updatedBy),
 | 
				
			||||||
            preData: this.mapUserToData(user),
 | 
					                deletedUser: user,
 | 
				
			||||||
        });
 | 
					            }),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async loginUser(usernameOrEmail: string, password: string): Promise<IUser> {
 | 
					    async loginUser(usernameOrEmail: string, password: string): Promise<IUser> {
 | 
				
			||||||
@ -479,5 +473,4 @@ class UserService {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = UserService;
 | 
					 | 
				
			||||||
export default UserService;
 | 
					export default UserService;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { extractUsernameFromUser } from '../util';
 | 
					import { extractUsernameFromUser } from '../util';
 | 
				
			||||||
import { FeatureToggle, IStrategyConfig, ITag, IVariant } from './model';
 | 
					import { FeatureToggle, IStrategyConfig, ITag, IVariant } from './model';
 | 
				
			||||||
import { IApiToken } from './models/api-token';
 | 
					import { IApiToken } from './models/api-token';
 | 
				
			||||||
import { IUser } from './user';
 | 
					import { IUser, IUserWithRootRole } from './user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const APPLICATION_CREATED = 'application-created' as const;
 | 
					export const APPLICATION_CREATED = 'application-created' as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1096,3 +1096,52 @@ export class PotentiallyStaleOnEvent extends BaseEvent {
 | 
				
			|||||||
        this.project = eventData.project;
 | 
					        this.project = eventData.project;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class UserCreatedEvent extends BaseEvent {
 | 
				
			||||||
 | 
					    readonly data: IUserWithRootRole;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(eventData: {
 | 
				
			||||||
 | 
					        createdBy: string | IUser;
 | 
				
			||||||
 | 
					        userCreated: IUserWithRootRole;
 | 
				
			||||||
 | 
					    }) {
 | 
				
			||||||
 | 
					        super(USER_CREATED, eventData.createdBy);
 | 
				
			||||||
 | 
					        this.data = mapUserToData(eventData.userCreated);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class UserUpdatedEvent extends BaseEvent {
 | 
				
			||||||
 | 
					    readonly data: IUserWithRootRole;
 | 
				
			||||||
 | 
					    readonly preData: IUserWithRootRole;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(eventData: {
 | 
				
			||||||
 | 
					        createdBy: string | IUser;
 | 
				
			||||||
 | 
					        preUser: IUserWithRootRole;
 | 
				
			||||||
 | 
					        postUser: IUserWithRootRole;
 | 
				
			||||||
 | 
					    }) {
 | 
				
			||||||
 | 
					        super(USER_UPDATED, eventData.createdBy);
 | 
				
			||||||
 | 
					        this.preData = mapUserToData(eventData.preUser);
 | 
				
			||||||
 | 
					        this.data = mapUserToData(eventData.postUser);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class UserDeletedEvent extends BaseEvent {
 | 
				
			||||||
 | 
					    readonly preData: IUserWithRootRole;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(eventData: {
 | 
				
			||||||
 | 
					        createdBy: string | IUser;
 | 
				
			||||||
 | 
					        deletedUser: IUserWithRootRole;
 | 
				
			||||||
 | 
					    }) {
 | 
				
			||||||
 | 
					        super(USER_DELETED, eventData.createdBy);
 | 
				
			||||||
 | 
					        this.preData = mapUserToData(eventData.deletedUser);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function mapUserToData(user: IUserWithRootRole): any {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        id: user.id,
 | 
				
			||||||
 | 
					        name: user.name,
 | 
				
			||||||
 | 
					        username: user.username,
 | 
				
			||||||
 | 
					        email: user.email,
 | 
				
			||||||
 | 
					        rootRole: user.rootRole,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,7 @@ export interface IAccessInfo {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IUserRole {
 | 
					export interface IUserRole {
 | 
				
			||||||
    roleId?: number;
 | 
					    roleId: number;
 | 
				
			||||||
    userId: number;
 | 
					    userId: number;
 | 
				
			||||||
    addedAt?: Date;
 | 
					    addedAt?: Date;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -188,6 +188,7 @@ export interface IAccessStore extends Store<IRole, number> {
 | 
				
			|||||||
        projectId: string,
 | 
					        projectId: string,
 | 
				
			||||||
        userId: number,
 | 
					        userId: number,
 | 
				
			||||||
    ): Promise<number[]>;
 | 
					    ): Promise<number[]>;
 | 
				
			||||||
 | 
					    getRootRoleForUser(userId: number): Promise<IRole | undefined>;
 | 
				
			||||||
    setProjectRolesForGroup(
 | 
					    setProjectRolesForGroup(
 | 
				
			||||||
        projectId: string,
 | 
					        projectId: string,
 | 
				
			||||||
        groupId: number,
 | 
					        groupId: number,
 | 
				
			||||||
 | 
				
			|||||||
@ -92,4 +92,8 @@ export default class User implements IUser {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IUserWithRootRole extends IUser {
 | 
				
			||||||
 | 
					    rootRole: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = User;
 | 
					module.exports = User;
 | 
				
			||||||
 | 
				
			|||||||
@ -37,7 +37,7 @@ test('editor users should only get client or frontend tokens', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.EDITOR);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.EDITOR);
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'editor@example.com',
 | 
					                email: 'editor@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -85,7 +85,7 @@ test('viewer users should not be allowed to fetch tokens', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.VIEWER);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.VIEWER);
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'viewer@example.com',
 | 
					                email: 'viewer@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -122,7 +122,7 @@ test('Only token-admins should be allowed to create token', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.EDITOR);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.EDITOR);
 | 
				
			||||||
            req.user = await userService.createUser({
 | 
					            req.user = await userService.createUser({
 | 
				
			||||||
                email: 'editor2@example.com',
 | 
					                email: 'editor2@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -150,7 +150,7 @@ test('Token-admin should be allowed to create token', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            req.user = await userService.createUser({
 | 
					            req.user = await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -185,7 +185,9 @@ test('A role with only CREATE_PROJECT_API_TOKEN can create project tokens', asyn
 | 
				
			|||||||
        }: { userService: UserService; accessService: AccessService },
 | 
					        }: { userService: UserService; accessService: AccessService },
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = (await accessService.getRootRole(RoleName.VIEWER))!;
 | 
					            const role = (await accessService.getPredefinedRole(
 | 
				
			||||||
 | 
					                RoleName.VIEWER,
 | 
				
			||||||
 | 
					            ))!;
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'powerpuffgirls_viewer@example.com',
 | 
					                email: 'powerpuffgirls_viewer@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -230,7 +232,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('should be allowed to create client tokens', async () => {
 | 
					        test('should be allowed to create client tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const builtInRole = await accessService.getRootRole(
 | 
					                    const builtInRole = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.VIEWER,
 | 
					                        RoleName.VIEWER,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -275,7 +277,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('should NOT be allowed to create frontend tokens', async () => {
 | 
					        test('should NOT be allowed to create frontend tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.VIEWER,
 | 
					                        RoleName.VIEWER,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -319,7 +321,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('should NOT be allowed to create ADMIN tokens', async () => {
 | 
					        test('should NOT be allowed to create ADMIN tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.VIEWER,
 | 
					                        RoleName.VIEWER,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -365,7 +367,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('READ_FRONTEND_API_TOKEN should be able to see FRONTEND tokens', async () => {
 | 
					        test('READ_FRONTEND_API_TOKEN should be able to see FRONTEND tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.VIEWER,
 | 
					                        RoleName.VIEWER,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -429,7 +431,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('READ_CLIENT_API_TOKEN should be able to see CLIENT tokens', async () => {
 | 
					        test('READ_CLIENT_API_TOKEN should be able to see CLIENT tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.VIEWER,
 | 
					                        RoleName.VIEWER,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -488,7 +490,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('Admin users should be able to see all tokens', async () => {
 | 
					        test('Admin users should be able to see all tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.ADMIN,
 | 
					                        RoleName.ADMIN,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -531,7 +533,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
        test('Editor users should be able to see all tokens except ADMIN tokens', async () => {
 | 
					        test('Editor users should be able to see all tokens except ADMIN tokens', async () => {
 | 
				
			||||||
            const preHook = (app, config, { userService, accessService }) => {
 | 
					            const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
                app.use('/api/admin/', async (req, res, next) => {
 | 
					                app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                    const role = await accessService.getRootRole(
 | 
					                    const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                        RoleName.EDITOR,
 | 
					                        RoleName.EDITOR,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    const user = await userService.createUser({
 | 
					                    const user = await userService.createUser({
 | 
				
			||||||
@ -585,7 +587,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
@ -634,7 +636,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
@ -684,7 +686,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
@ -737,7 +739,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
@ -786,7 +788,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
@ -835,7 +837,7 @@ describe('Fine grained API token permissions', () => {
 | 
				
			|||||||
                    { userService, accessService },
 | 
					                    { userService, accessService },
 | 
				
			||||||
                ) => {
 | 
					                ) => {
 | 
				
			||||||
                    app.use('/api/admin/', async (req, res, next) => {
 | 
					                    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
                        const role = await accessService.getRootRole(
 | 
					                        const role = await accessService.getPredefinedRole(
 | 
				
			||||||
                            RoleName.VIEWER,
 | 
					                            RoleName.VIEWER,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                        const user = await userService.createUser({
 | 
					                        const user = await userService.createUser({
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@ test('admin users should be able to create a token', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -69,7 +69,7 @@ test('admin users should be able to create a token', async () => {
 | 
				
			|||||||
test('no permission to validate a token', async () => {
 | 
					test('no permission to validate a token', async () => {
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const admin = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const admin = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            await userService.createUser({
 | 
					            await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                username: 'admin@example.com',
 | 
					                username: 'admin@example.com',
 | 
				
			||||||
@ -97,7 +97,7 @@ test('no permission to validate a token', async () => {
 | 
				
			|||||||
test('should return 400 if token can not be validate', async () => {
 | 
					test('should return 400 if token can not be validate', async () => {
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const admin = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const admin = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            await userService.createUser({
 | 
					            await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                username: 'admin@example.com',
 | 
					                username: 'admin@example.com',
 | 
				
			||||||
@ -119,7 +119,7 @@ test('users can signup with invite-link', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const admin = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const admin = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            await userService.createUser({
 | 
					            await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                username: 'admin@example.com',
 | 
					                username: 'admin@example.com',
 | 
				
			||||||
@ -164,7 +164,7 @@ test('can get a token with users', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
@ -209,7 +209,7 @@ test('can get a token with users', async () => {
 | 
				
			|||||||
test('should not be able to set expiry further than 1 month', async () => {
 | 
					test('should not be able to set expiry further than 1 month', async () => {
 | 
				
			||||||
    const preHook = (app, config, { userService, accessService }) => {
 | 
					    const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
        app.use('/api/admin/', async (req, res, next) => {
 | 
					        app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
            const role = await accessService.getRootRole(RoleName.ADMIN);
 | 
					            const role = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
            const user = await userService.createUser({
 | 
					            const user = await userService.createUser({
 | 
				
			||||||
                email: 'admin@example.com',
 | 
					                email: 'admin@example.com',
 | 
				
			||||||
                rootRole: role.id,
 | 
					                rootRole: role.id,
 | 
				
			||||||
 | 
				
			|||||||
@ -80,13 +80,13 @@ beforeAll(async () => {
 | 
				
			|||||||
        settingService,
 | 
					        settingService,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    resetTokenService = new ResetTokenService(stores, config);
 | 
					    resetTokenService = new ResetTokenService(stores, config);
 | 
				
			||||||
    const adminRole = (await accessService.getRootRole(RoleName.ADMIN))!;
 | 
					    const adminRole = (await accessService.getPredefinedRole(RoleName.ADMIN))!;
 | 
				
			||||||
    adminUser = await userService.createUser({
 | 
					    adminUser = await userService.createUser({
 | 
				
			||||||
        username: 'admin@test.com',
 | 
					        username: 'admin@test.com',
 | 
				
			||||||
        rootRole: adminRole.id,
 | 
					        rootRole: adminRole.id,
 | 
				
			||||||
    })!;
 | 
					    })!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const userRole = (await accessService.getRootRole(RoleName.EDITOR))!;
 | 
					    const userRole = (await accessService.getPredefinedRole(RoleName.EDITOR))!;
 | 
				
			||||||
    user = await userService.createUser({
 | 
					    user = await userService.createUser({
 | 
				
			||||||
        username: 'test@test.com',
 | 
					        username: 'test@test.com',
 | 
				
			||||||
        email: 'test@test.com',
 | 
					        email: 'test@test.com',
 | 
				
			||||||
 | 
				
			|||||||
@ -56,7 +56,7 @@ beforeAll(async () => {
 | 
				
			|||||||
        sessionService,
 | 
					        sessionService,
 | 
				
			||||||
        settingService,
 | 
					        settingService,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    const adminRole = await accessService.getRootRole(RoleName.ADMIN);
 | 
					    const adminRole = await accessService.getPredefinedRole(RoleName.ADMIN);
 | 
				
			||||||
    adminUser = await userService.createUser({
 | 
					    adminUser = await userService.createUser({
 | 
				
			||||||
        username: 'admin@test.com',
 | 
					        username: 'admin@test.com',
 | 
				
			||||||
        email: 'admin@test.com',
 | 
					        email: 'admin@test.com',
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ let stores;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const preHook = (app, config, { userService, accessService }) => {
 | 
					const preHook = (app, config, { userService, accessService }) => {
 | 
				
			||||||
    app.use('/api/admin/', async (req, res, next) => {
 | 
					    app.use('/api/admin/', async (req, res, next) => {
 | 
				
			||||||
        const role = await accessService.getRootRole(RoleName.EDITOR);
 | 
					        const role = await accessService.getPredefinedRole(RoleName.EDITOR);
 | 
				
			||||||
        req.user = await userService.createUser({
 | 
					        req.user = await userService.createUser({
 | 
				
			||||||
            email: 'editor2@example.com',
 | 
					            email: 'editor2@example.com',
 | 
				
			||||||
            rootRole: role.id,
 | 
					            rootRole: role.id,
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ import { randomId } from '../../../lib/util/random-id';
 | 
				
			|||||||
import { BadDataError } from '../../../lib/error';
 | 
					import { BadDataError } from '../../../lib/error';
 | 
				
			||||||
import PasswordMismatch from '../../../lib/error/password-mismatch';
 | 
					import PasswordMismatch from '../../../lib/error/password-mismatch';
 | 
				
			||||||
import { EventService } from '../../../lib/services';
 | 
					import { EventService } from '../../../lib/services';
 | 
				
			||||||
 | 
					import { USER_CREATED, USER_DELETED, USER_UPDATED } from '../../../lib/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let db;
 | 
					let db;
 | 
				
			||||||
let stores;
 | 
					let stores;
 | 
				
			||||||
@ -27,12 +28,13 @@ let adminRole: IRole;
 | 
				
			|||||||
let viewerRole: IRole;
 | 
					let viewerRole: IRole;
 | 
				
			||||||
let sessionService: SessionService;
 | 
					let sessionService: SessionService;
 | 
				
			||||||
let settingService: SettingService;
 | 
					let settingService: SettingService;
 | 
				
			||||||
 | 
					let eventService: EventService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
beforeAll(async () => {
 | 
					beforeAll(async () => {
 | 
				
			||||||
    db = await dbInit('user_service_serial', getLogger);
 | 
					    db = await dbInit('user_service_serial', getLogger);
 | 
				
			||||||
    stores = db.stores;
 | 
					    stores = db.stores;
 | 
				
			||||||
    const config = createTestConfig();
 | 
					    const config = createTestConfig();
 | 
				
			||||||
    const eventService = new EventService(stores, config);
 | 
					    eventService = new EventService(stores, config);
 | 
				
			||||||
    const groupService = new GroupService(stores, config, eventService);
 | 
					    const groupService = new GroupService(stores, config, eventService);
 | 
				
			||||||
    const accessService = new AccessService(
 | 
					    const accessService = new AccessService(
 | 
				
			||||||
        stores,
 | 
					        stores,
 | 
				
			||||||
@ -124,6 +126,49 @@ test('should create user with password', async () => {
 | 
				
			|||||||
    expect(user.username).toBe('test');
 | 
					    expect(user.username).toBe('test');
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should create user with rootRole in audit-log', async () => {
 | 
				
			||||||
 | 
					    const user = await userService.createUser({
 | 
				
			||||||
 | 
					        username: 'test',
 | 
				
			||||||
 | 
					        rootRole: viewerRole.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { events } = await eventService.getEvents();
 | 
				
			||||||
 | 
					    expect(events[0].type).toBe(USER_CREATED);
 | 
				
			||||||
 | 
					    expect(events[0].data.id).toBe(user.id);
 | 
				
			||||||
 | 
					    expect(events[0].data.username).toBe('test');
 | 
				
			||||||
 | 
					    expect(events[0].data.rootRole).toBe(viewerRole.id);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should update user with rootRole in audit-log', async () => {
 | 
				
			||||||
 | 
					    const user = await userService.createUser({
 | 
				
			||||||
 | 
					        username: 'test',
 | 
				
			||||||
 | 
					        rootRole: viewerRole.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await userService.updateUser({ id: user.id, rootRole: adminRole.id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { events } = await eventService.getEvents();
 | 
				
			||||||
 | 
					    expect(events[0].type).toBe(USER_UPDATED);
 | 
				
			||||||
 | 
					    expect(events[0].data.id).toBe(user.id);
 | 
				
			||||||
 | 
					    expect(events[0].data.username).toBe('test');
 | 
				
			||||||
 | 
					    expect(events[0].data.rootRole).toBe(adminRole.id);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should remove user with rootRole in audit-log', async () => {
 | 
				
			||||||
 | 
					    const user = await userService.createUser({
 | 
				
			||||||
 | 
					        username: 'test',
 | 
				
			||||||
 | 
					        rootRole: viewerRole.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await userService.deleteUser(user.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { events } = await eventService.getEvents();
 | 
				
			||||||
 | 
					    expect(events[0].type).toBe(USER_DELETED);
 | 
				
			||||||
 | 
					    expect(events[0].preData.id).toBe(user.id);
 | 
				
			||||||
 | 
					    expect(events[0].preData.username).toBe('test');
 | 
				
			||||||
 | 
					    expect(events[0].preData.rootRole).toBe(viewerRole.id);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should not be able to login with deleted user', async () => {
 | 
					test('should not be able to login with deleted user', async () => {
 | 
				
			||||||
    const user = await userService.createUser({
 | 
					    const user = await userService.createUser({
 | 
				
			||||||
        username: 'deleted_user',
 | 
					        username: 'deleted_user',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								src/test/fixtures/access-service-mock.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								src/test/fixtures/access-service-mock.ts
									
									
									
									
										vendored
									
									
								
							@ -7,7 +7,7 @@ import {
 | 
				
			|||||||
import User from '../../lib/types/user';
 | 
					import User from '../../lib/types/user';
 | 
				
			||||||
import noLoggerProvider from './no-logger';
 | 
					import noLoggerProvider from './no-logger';
 | 
				
			||||||
import { IRole } from '../../lib/types/stores/access-store';
 | 
					import { IRole } from '../../lib/types/stores/access-store';
 | 
				
			||||||
import { IAvailablePermissions } from '../../lib/types/model';
 | 
					import { IAvailablePermissions, RoleName } from '../../lib/types/model';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccessServiceMock extends AccessService {
 | 
					class AccessServiceMock extends AccessService {
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
@ -69,7 +69,11 @@ class AccessServiceMock extends AccessService {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getRolesForUser(userId: number): Promise<IRole[]> {
 | 
					    getRolesForUser(userId: number): Promise<IRole[]> {
 | 
				
			||||||
        throw new Error('Method not implemented.');
 | 
					        return Promise.resolve([{ id: 1, name: 'Admin', type: 'root' }]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getUserRootRoles(userId: number): Promise<IRole[]> {
 | 
				
			||||||
 | 
					        return Promise.resolve([{ id: 1, name: 'Admin', type: 'root' }]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getUsersForRole(roleId: any): Promise<User[]> {
 | 
					    getUsersForRole(roleId: any): Promise<User[]> {
 | 
				
			||||||
@ -87,6 +91,14 @@ class AccessServiceMock extends AccessService {
 | 
				
			|||||||
    removeDefaultProjectRoles(owner: User, projectId: string): Promise<void> {
 | 
					    removeDefaultProjectRoles(owner: User, projectId: string): Promise<void> {
 | 
				
			||||||
        throw new Error('Method not implemented.');
 | 
					        throw new Error('Method not implemented.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getRootRole(roleName: RoleName): Promise<IRole> {
 | 
				
			||||||
 | 
					        return Promise.resolve({ id: 1, name: roleName, type: 'root' });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getRootRoleForUser(userId: number): Promise<IRole> {
 | 
				
			||||||
 | 
					        return Promise.resolve({ id: 1, name: RoleName.VIEWER, type: 'root' });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default AccessServiceMock;
 | 
					export default AccessServiceMock;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								src/test/fixtures/fake-access-store.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								src/test/fixtures/fake-access-store.ts
									
									
									
									
										vendored
									
									
								
							@ -9,8 +9,13 @@ import {
 | 
				
			|||||||
    IUserRole,
 | 
					    IUserRole,
 | 
				
			||||||
    IUserWithProjectRoles,
 | 
					    IUserWithProjectRoles,
 | 
				
			||||||
} from '../../lib/types/stores/access-store';
 | 
					} from '../../lib/types/stores/access-store';
 | 
				
			||||||
import { IPermission } from 'lib/types/model';
 | 
					import { IPermission } from '../../lib/types/model';
 | 
				
			||||||
import { IRoleStore, IUserAccessOverview } from 'lib/types';
 | 
					import {
 | 
				
			||||||
 | 
					    IRoleStore,
 | 
				
			||||||
 | 
					    IUserAccessOverview,
 | 
				
			||||||
 | 
					    RoleName,
 | 
				
			||||||
 | 
					    RoleType,
 | 
				
			||||||
 | 
					} from '../../lib/types';
 | 
				
			||||||
import FakeRoleStore from './fake-role-store';
 | 
					import FakeRoleStore from './fake-role-store';
 | 
				
			||||||
import { PermissionRef } from 'lib/services/access-service';
 | 
					import { PermissionRef } from 'lib/services/access-service';
 | 
				
			||||||
import { P } from 'ts-toolbelt/out/Object/_api';
 | 
					import { P } from 'ts-toolbelt/out/Object/_api';
 | 
				
			||||||
@ -302,6 +307,18 @@ class AccessStoreMock implements IAccessStore {
 | 
				
			|||||||
    getUserAccessOverview(): Promise<IUserAccessOverview[]> {
 | 
					    getUserAccessOverview(): Promise<IUserAccessOverview[]> {
 | 
				
			||||||
        throw new Error('Method not implemented.');
 | 
					        throw new Error('Method not implemented.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    getRootRoleForUser(userId: number): Promise<IRole> {
 | 
				
			||||||
 | 
					        const roleId = this.userToRoleMap.get(userId);
 | 
				
			||||||
 | 
					        if (roleId !== undefined) {
 | 
				
			||||||
 | 
					            return Promise.resolve(this.fakeRolesStore.get(roleId));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return Promise.resolve({
 | 
				
			||||||
 | 
					                id: -1,
 | 
				
			||||||
 | 
					                name: RoleName.VIEWER,
 | 
				
			||||||
 | 
					                type: RoleType.ROOT,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = AccessStoreMock;
 | 
					module.exports = AccessStoreMock;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user