Skip to content

Commit

Permalink
fix typing errors
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Jun 10, 2024
1 parent e00a64f commit 1e3db1e
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 69 deletions.
7 changes: 6 additions & 1 deletion packages/cli/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import type PCancelable from 'p-cancelable';
import type { AuthProviderType } from '@db/entities/AuthIdentity';
import type { SharedCredentials } from '@db/entities/SharedCredentials';
import type { TagEntity } from '@db/entities/TagEntity';
import type { GlobalRole, User } from '@db/entities/User';
import type { AssignableRole, GlobalRole, User } from '@db/entities/User';
import type { CredentialsRepository } from '@db/repositories/credentials.repository';
import type { SettingsRepository } from '@db/repositories/settings.repository';
import type { UserRepository } from '@db/repositories/user.repository';
Expand Down Expand Up @@ -634,6 +634,11 @@ export interface PublicUser {
featureFlags?: FeatureFlags;
}

export interface Invitation {
email: string;
role: AssignableRole;
}

export interface N8nApp {
app: Application;
restEndpoint: string;
Expand Down
14 changes: 3 additions & 11 deletions packages/cli/src/databases/entities/AuthUser.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { Column, Entity, PrimaryColumn } from '@n8n/typeorm';
import { Column, Entity } from '@n8n/typeorm';
import { User } from './User';

@Entity({ name: 'user' })
export class AuthUser {
@PrimaryColumn({ type: 'uuid', update: false })
id: string;

@Column({ type: String, update: false })
email: string;

@Column({ type: Boolean, default: false })
mfaEnabled: boolean;

export class AuthUser extends User {
@Column({ type: String, nullable: true })
mfaSecret?: string | null;

Expand Down
27 changes: 15 additions & 12 deletions packages/cli/src/services/hooks.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { Service } from 'typedi';
import { UserService } from '@/services/user.service';
import type { AssignableRole, User } from '@/databases/entities/User';
import { AuthService } from '@/auth/auth.service';
import type { NextFunction, Response } from 'express';
import { UserRepository } from '@/databases/repositories/user.repository';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
import type { QueryDeepPartialEntity } from '@n8n/typeorm/query-builder/QueryPartialEntity';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
import type { FindManyOptions, FindOneOptions, FindOptionsWhere } from '@n8n/typeorm';
import type { WorkflowEntity } from '@/databases/entities/WorkflowEntity';
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import type { Settings } from '@/databases/entities/Settings';

import { AuthService } from '@/auth/auth.service';
import type { AuthUser } from '@db/entities/AuthUser';
import type { User } from '@db/entities/User';
import { UserRepository } from '@db/repositories/user.repository';
import { SettingsRepository } from '@db/repositories/settings.repository';
import { WorkflowRepository } from '@db/repositories/workflow.repository';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import type { Settings } from '@db/entities/Settings';
import { UserService } from '@/services/user.service';
import type { AuthenticatedRequest } from '@/requests';
import type { Invitation } from '@/Interfaces';

/**
* Exposes functionality to be used by the cloud BE hooks.
Expand All @@ -32,15 +35,15 @@ export class HooksService {
/**
* Invite users to instance during signup
*/
async inviteUsers(owner: User, attributes: Array<{ email: string; role: AssignableRole }>) {
async inviteUsers(owner: AuthUser, attributes: Invitation[]) {
return await this.userService.inviteUsers(owner, attributes);
}

/**
* Set the n8n-auth cookie in the response to auto-login
* the user after instance is provisioned
*/
issueCookie(res: Response, user: User) {
issueCookie(res: Response, user: AuthUser) {
return this.authService.issueCookie(res, user);
}

Expand Down
10 changes: 5 additions & 5 deletions packages/cli/src/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ApplicationError, ErrorReporterProxy as ErrorReporter } from 'n8n-workf

import type { User, AssignableRole } from '@db/entities/User';
import { UserRepository } from '@db/repositories/user.repository';
import type { PublicUser } from '@/Interfaces';
import type { Invitation, PublicUser } from '@/Interfaces';
import type { PostHogClient } from '@/posthog';
import { Logger } from '@/Logger';
import { UserManagementMailer } from '@/UserManagement/email';
Expand Down Expand Up @@ -178,14 +178,14 @@ export class UserService {
);
}

async inviteUsers(owner: User, attributes: Array<{ email: string; role: AssignableRole }>) {
const emails = attributes.map(({ email }) => email);
async inviteUsers(owner: User, invitations: Invitation[]) {
const emails = invitations.map(({ email }) => email);

const existingUsers = await this.userRepository.findManyByEmail(emails);

const existUsersEmails = existingUsers.map((user) => user.email);

const toCreateUsers = attributes.filter(({ email }) => !existUsersEmails.includes(email));
const toCreateUsers = invitations.filter(({ email }) => !existUsersEmails.includes(email));

const pendingUsersToInvite = existingUsers.filter((email) => email.isPending);

Expand Down Expand Up @@ -222,7 +222,7 @@ export class UserService {
const usersInvited = await this.sendEmails(
owner,
Object.fromEntries(createdUsers),
attributes[0].role, // same role for all invited users
invitations[0].role, // same role for all invited users
);

return { usersInvited, usersCreated: toCreateUsers.map(({ email }) => email) };
Expand Down
64 changes: 24 additions & 40 deletions packages/cli/test/unit/services/hooks.service.test.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import { UserService } from '@/services/user.service';
import { HooksService } from '@/services/hooks.service';
import { User } from '@/databases/entities/User';
import { mockInstance } from '../../shared/mocking';
import { v4 as uuid } from 'uuid';
import { AuthService } from '@/auth/auth.service';
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
import { SettingsRepository } from '@/databases/repositories/settings.repository';
import { UserRepository } from '@/databases/repositories/user.repository';
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
import type { Response } from 'express';

let hooksService: HooksService;

const mockedUser = Object.assign(new User(), {
id: uuid(),
password: 'passwordHash',
mfaEnabled: false,
mfaSecret: 'test',
mfaRecoveryCodes: ['test'],
updatedAt: new Date(),
});
import { mock } from 'jest-mock-extended';

import type { AuthUser } from '@db/entities/AuthUser';
import type { CredentialsRepository } from '@db/repositories/credentials.repository';
import type { SettingsRepository } from '@db/repositories/settings.repository';
import type { UserRepository } from '@db/repositories/user.repository';
import type { WorkflowRepository } from '@db/repositories/workflow.repository';
import type { AuthService } from '@/auth/auth.service';
import type { UserService } from '@/services/user.service';
import { HooksService } from '@/services/hooks.service';
import type { Invitation } from '@/Interfaces';
import type { AuthenticatedRequest } from '@/requests';

describe('HooksService', () => {
const userService = mockInstance(UserService);
const authService = mockInstance(AuthService);
const userRepository = mockInstance(UserRepository);
const settingsRepository = mockInstance(SettingsRepository);
const workflowRepository = mockInstance(WorkflowRepository);
const credentialsRepository = mockInstance(CredentialsRepository);
hooksService = new HooksService(
const mockedUser = mock<AuthUser>();
const userService = mock<UserService>();
const authService = mock<AuthService>();
const userRepository = mock<UserRepository>();
const settingsRepository = mock<SettingsRepository>();
const workflowRepository = mock<WorkflowRepository>();
const credentialsRepository = mock<CredentialsRepository>();
const hooksService = new HooksService(
userService,
authService,
userRepository,
Expand All @@ -43,9 +35,7 @@ describe('HooksService', () => {

it('hooksService.inviteUsers should call userService.inviteUsers', async () => {
// ARRANGE
const usersToInvite: Parameters<typeof userService.inviteUsers>[1] = [
{ email: '[email protected]', role: 'global:member' },
];
const usersToInvite: Invitation[] = [{ email: '[email protected]', role: 'global:member' }];

// ACT
await hooksService.inviteUsers(mockedUser, usersToInvite);
Expand All @@ -56,9 +46,7 @@ describe('HooksService', () => {

it('hooksService.issueCookie should call authService.issueCookie', async () => {
// ARRANGE
const res = {
cookie: jest.fn(),
} as unknown as Response;
const res = mock<Response>();

// ACT
hooksService.issueCookie(res, mockedUser);
Expand Down Expand Up @@ -134,13 +122,9 @@ describe('HooksService', () => {

it('hooksService.authMiddleware should call authService.authMiddleware', async () => {
// ARRANGE
const res = {
cookie: jest.fn(),
} as unknown as Response;
const res = mock<Response>();

const req = {
cookie: jest.fn(),
} as unknown as Response;
const req = mock<AuthenticatedRequest>();

const next = jest.fn();

Expand Down

0 comments on commit 1e3db1e

Please sign in to comment.