refactor(core): Decouple event bus from internal hooks (no-changelog) (#9724)

This commit is contained in:
Iván Ovejero
2024-06-20 12:32:22 +02:00
committed by GitHub
parent e4463c62b4
commit 199dff4fb3
29 changed files with 1028 additions and 664 deletions

View File

@@ -24,6 +24,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
import { ApplicationError } from 'n8n-workflow';
import { UserRepository } from '@/databases/repositories/user.repository';
import { EventRelay } from '@/eventbus/event-relay.service';
@RestController()
export class AuthController {
@@ -35,6 +36,7 @@ export class AuthController {
private readonly userService: UserService,
private readonly license: License,
private readonly userRepository: UserRepository,
private readonly eventRelay: EventRelay,
private readonly postHog?: PostHogClient,
) {}
@@ -90,16 +92,17 @@ export class AuthController {
}
this.authService.issueCookie(res, user, req.browserId);
void this.internalHooks.onUserLoginSuccess({
this.eventRelay.emit('user-logged-in', {
user,
authenticationMethod: usedAuthenticationMethod,
});
return await this.userService.toPublic(user, { posthog: this.postHog, withScopes: true });
}
void this.internalHooks.onUserLoginFailed({
user: email,
this.eventRelay.emit('user-login-failed', {
authenticationMethod: usedAuthenticationMethod,
userEmail: email,
reason: 'wrong credentials',
});
throw new AuthError('Wrong username or password. Do you have caps lock on?');
@@ -177,6 +180,7 @@ export class AuthController {
}
void this.internalHooks.onUserInviteEmailClick({ inviter, invitee });
this.eventRelay.emit('user-invite-email-click', { inviter, invitee });
const { firstName, lastName } = inviter;
return { inviter: { firstName, lastName } };

View File

@@ -14,6 +14,7 @@ import { Push } from '@/push';
import { CommunityPackagesService } from '@/services/communityPackages.service';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
import { EventRelay } from '@/eventbus/event-relay.service';
const {
PACKAGE_NOT_INSTALLED,
@@ -38,6 +39,7 @@ export class CommunityPackagesController {
private readonly push: Push,
private readonly internalHooks: InternalHooks,
private readonly communityPackagesService: CommunityPackagesService,
private readonly eventRelay: EventRelay,
) {}
// TODO: move this into a new decorator `@IfConfig('executions.mode', 'queue')`
@@ -114,6 +116,14 @@ export class CommunityPackagesController {
package_version: parsed.version,
failure_reason: errorMessage,
});
this.eventRelay.emit('community-package-installed', {
user: req.user,
inputString: name,
packageName: parsed.packageName,
success: false,
packageVersion: parsed.version,
failureReason: errorMessage,
});
let message = [`Error loading package "${name}" `, errorMessage].join(':');
if (error instanceof Error && error.cause instanceof Error) {
@@ -144,6 +154,16 @@ export class CommunityPackagesController {
package_author: installedPackage.authorName,
package_author_email: installedPackage.authorEmail,
});
this.eventRelay.emit('community-package-installed', {
user: req.user,
inputString: name,
packageName: parsed.packageName,
success: true,
packageVersion: parsed.version,
packageNodeNames: installedPackage.installedNodes.map((node) => node.name),
packageAuthor: installedPackage.authorName,
packageAuthorEmail: installedPackage.authorEmail,
});
return installedPackage;
}
@@ -233,6 +253,14 @@ export class CommunityPackagesController {
package_author: installedPackage.authorName,
package_author_email: installedPackage.authorEmail,
});
this.eventRelay.emit('community-package-deleted', {
user: req.user,
packageName: name,
packageVersion: installedPackage.installedVersion,
packageNodeNames: installedPackage.installedNodes.map((node) => node.name),
packageAuthor: installedPackage.authorName,
packageAuthorEmail: installedPackage.authorEmail,
});
}
@Patch('/')
@@ -281,6 +309,15 @@ export class CommunityPackagesController {
package_author: newInstalledPackage.authorName,
package_author_email: newInstalledPackage.authorEmail,
});
this.eventRelay.emit('community-package-updated', {
user: req.user,
packageName: name,
packageVersionCurrent: previouslyInstalledPackage.installedVersion,
packageVersionNew: newInstalledPackage.installedVersion,
packageNodeNames: newInstalledPackage.installedNodes.map((n) => n.name),
packageAuthor: newInstalledPackage.authorName,
packageAuthorEmail: newInstalledPackage.authorEmail,
});
return newInstalledPackage;
} catch (error) {

View File

@@ -18,6 +18,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
import { InternalHooks } from '@/InternalHooks';
import { ExternalHooks } from '@/ExternalHooks';
import { EventRelay } from '@/eventbus/event-relay.service';
@RestController('/invitations')
export class InvitationController {
@@ -31,6 +32,7 @@ export class InvitationController {
private readonly passwordUtility: PasswordUtility,
private readonly userRepository: UserRepository,
private readonly postHog: PostHogClient,
private readonly eventRelay: EventRelay,
) {}
/**
@@ -170,6 +172,7 @@ export class InvitationController {
user_type: 'email',
was_disabled_ldap_user: false,
});
this.eventRelay.emit('user-signed-up', { user: updatedUser });
const publicInvitee = await this.userService.toPublic(invitee);

View File

@@ -23,6 +23,7 @@ import { InternalHooks } from '@/InternalHooks';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { UserRepository } from '@/databases/repositories/user.repository';
import { isApiEnabled } from '@/PublicApi';
import { EventRelay } from '@/eventbus/event-relay.service';
export const isApiEnabledMiddleware: RequestHandler = (_, res, next) => {
if (isApiEnabled()) {
@@ -42,6 +43,7 @@ export class MeController {
private readonly userService: UserService,
private readonly passwordUtility: PasswordUtility,
private readonly userRepository: UserRepository,
private readonly eventRelay: EventRelay,
) {}
/**
@@ -96,11 +98,9 @@ export class MeController {
this.authService.issueCookie(res, user, req.browserId);
const updatedKeys = Object.keys(payload);
void this.internalHooks.onUserUpdate({
user,
fields_changed: updatedKeys,
});
const fieldsChanged = Object.keys(payload);
void this.internalHooks.onUserUpdate({ user, fields_changed: fieldsChanged });
this.eventRelay.emit('user-updated', { user, fieldsChanged });
const publicUser = await this.userService.toPublic(user);
@@ -149,10 +149,8 @@ export class MeController {
this.authService.issueCookie(res, updatedUser, req.browserId);
void this.internalHooks.onUserUpdate({
user: updatedUser,
fields_changed: ['password'],
});
void this.internalHooks.onUserUpdate({ user: updatedUser, fields_changed: ['password'] });
this.eventRelay.emit('user-updated', { user: updatedUser, fieldsChanged: ['password'] });
await this.externalHooks.run('user.password.update', [updatedUser.email, updatedUser.password]);
@@ -200,10 +198,8 @@ export class MeController {
await this.userService.update(req.user.id, { apiKey });
void this.internalHooks.onApiKeyCreated({
user: req.user,
public_api: false,
});
void this.internalHooks.onApiKeyCreated({ user: req.user, public_api: false });
this.eventRelay.emit('api-key-created', { user: req.user });
return { apiKey };
}
@@ -223,10 +219,8 @@ export class MeController {
async deleteAPIKey(req: AuthenticatedRequest) {
await this.userService.update(req.user.id, { apiKey: null });
void this.internalHooks.onApiKeyDeleted({
user: req.user,
public_api: false,
});
void this.internalHooks.onApiKeyDeleted({ user: req.user, public_api: false });
this.eventRelay.emit('api-key-deleted', { user: req.user });
return { success: true };
}

View File

@@ -21,6 +21,7 @@ import { ForbiddenError } from '@/errors/response-errors/forbidden.error';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error';
import { UserRepository } from '@/databases/repositories/user.repository';
import { EventRelay } from '@/eventbus/event-relay.service';
@RestController()
export class PasswordResetController {
@@ -36,6 +37,7 @@ export class PasswordResetController {
private readonly license: License,
private readonly passwordUtility: PasswordUtility,
private readonly userRepository: UserRepository,
private readonly eventRelay: EventRelay,
) {}
/**
@@ -123,6 +125,7 @@ export class PasswordResetController {
message_type: 'Reset password',
public_api: false,
});
this.eventRelay.emit('email-failed', { user, messageType: 'Reset password' });
if (error instanceof Error) {
throw new InternalServerError(`Please contact your administrator: ${error.message}`);
}
@@ -136,6 +139,7 @@ export class PasswordResetController {
});
void this.internalHooks.onUserPasswordResetRequestClick({ user });
this.eventRelay.emit('user-password-reset-request-click', { user });
}
/**
@@ -168,6 +172,7 @@ export class PasswordResetController {
this.logger.info('Reset-password token resolved successfully', { userId: user.id });
void this.internalHooks.onUserPasswordResetEmailClick({ user });
this.eventRelay.emit('user-password-reset-email-click', { user });
}
/**
@@ -210,10 +215,8 @@ export class PasswordResetController {
this.authService.issueCookie(res, user, req.browserId);
void this.internalHooks.onUserUpdate({
user,
fields_changed: ['password'],
});
void this.internalHooks.onUserUpdate({ user, fields_changed: ['password'] });
this.eventRelay.emit('user-updated', { user, fieldsChanged: ['password'] });
// if this user used to be an LDAP users
const ldapIdentity = user?.authIdentities?.find((i) => i.providerType === 'ldap');
@@ -222,6 +225,7 @@ export class PasswordResetController {
user_type: 'email',
was_disabled_ldap_user: true,
});
this.eventRelay.emit('user-signed-up', { user });
}
await this.externalHooks.run('user.password.update', [user.email, passwordHash]);

View File

@@ -28,6 +28,7 @@ import { Project } from '@/databases/entities/Project';
import { WorkflowService } from '@/workflows/workflow.service';
import { CredentialsService } from '@/credentials/credentials.service';
import { ProjectService } from '@/services/project.service';
import { EventRelay } from '@/eventbus/event-relay.service';
@RestController('/users')
export class UsersController {
@@ -44,6 +45,7 @@ export class UsersController {
private readonly workflowService: WorkflowService,
private readonly credentialsService: CredentialsService,
private readonly projectService: ProjectService,
private readonly eventRelay: EventRelay,
) {}
static ERROR_MESSAGES = {
@@ -256,6 +258,7 @@ export class UsersController {
telemetryData,
publicApi: false,
});
this.eventRelay.emit('user-deleted', { user: req.user });
await this.externalHooks.run('user.deleted', [await this.userService.toPublic(userToDelete)]);