Skip to content

Commit b7daeb8

Browse files
authored
Migrate Events -> SC Hooks (#3548)
Begins move from `~/core/events` to `~/core/hooks` which is just the rebranded v2 of _events_ that is in our library. I swapped out the underlying implementation here for the hooks module, and gave a few migration examples. But I left most of the old code as deprecated for future clean up. In general we are just renaming: - `events/` -> `hooks/` - `XEvent` -> `XHook` - `IEventBus` -> `Hooks` - `@EventHandler(...)` -> `@OnHook(...)` Only real change, is the priority ordering is flipped, so lower numbers come first now. So just flip the sign of the priority declared in decorator. More info here: SeedCompany/libs#60
2 parents 6270495 + 9d4a2a5 commit b7daeb8

14 files changed

+78
-156
lines changed

.eslintrc.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ const restrictedImports = [
103103
path: 'gql.tada',
104104
replacement: { path: '~/graphql' },
105105
},
106+
{
107+
path: '@seedcompany/nest/hooks',
108+
replacement: { path: '~/core/hooks' },
109+
message: 'Reference from core instead to keep loose coupling',
110+
},
106111
];
107112

108113
const namingConvention = [

src/components/authorization/authorization.module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
SessionExtraInfoResolver,
88
} from './authorization.resolver';
99
import { BetaFeaturesGranter } from './dto/beta-features.dto';
10-
import { CanImpersonateHandler } from './handler/can-impersonate.handler';
10+
import { CanImpersonateViaPrivilegesHandler } from './handler/can-impersonate-via-privileges.handler';
1111
import * as Policies from './policies';
1212
import { PolicyModule } from './policy/policy.module';
1313

@@ -19,7 +19,7 @@ import { PolicyModule } from './policy/policy.module';
1919
LoginExtraInfoResolver,
2020
RegisterExtraInfoResolver,
2121
SessionExtraInfoResolver,
22-
CanImpersonateHandler,
22+
CanImpersonateViaPrivilegesHandler,
2323
...Object.values(Policies),
2424
AssignableRolesGranter,
2525
BetaFeaturesGranter,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { CanImpersonateHook } from '~/core/authentication/hooks/can-impersonate.hook';
3+
import { OnHook } from '~/core/hooks';
4+
import { AssignableRoles } from '../dto/assignable-roles.dto';
5+
import { Privileges } from '../policy';
6+
7+
@Injectable()
8+
export class CanImpersonateViaPrivilegesHandler {
9+
constructor(private readonly privileges: Privileges) {}
10+
11+
@OnHook(CanImpersonateHook)
12+
canImpersonate({ session, allow }: CanImpersonateHook) {
13+
const p = this.privileges.for(AssignableRoles);
14+
const granted = session.roles.values().every((role) => p.can('edit', role));
15+
allow.vote(granted);
16+
}
17+
}

src/components/authorization/handler/can-impersonate.handler.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/components/engagement/handlers/validate-eng-date-overrides-on-project-change.handler.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import { Injectable } from '@nestjs/common';
12
import { DateOverrideConflictException, EnhancedResource } from '~/common';
2-
import { EventsHandler, type IEventHandler } from '~/core';
3+
import { OnHook } from '~/core/hooks';
34
import { ProjectUpdatedEvent } from '../../project/events';
45
import { EngagementService } from '../engagement.service';
56

6-
@EventsHandler([ProjectUpdatedEvent, 10])
7-
export class ValidateEngDateOverridesOnProjectChangeHandler
8-
implements IEventHandler<ProjectUpdatedEvent>
9-
{
7+
@Injectable()
8+
export class ValidateEngDateOverridesOnProjectChangeHandler {
109
constructor(private readonly engagements: EngagementService) {}
1110

11+
@OnHook(ProjectUpdatedEvent, -10)
1212
async handle(event: ProjectUpdatedEvent) {
1313
const { updated: project, changes } = event;
1414

src/components/periodic-report/handlers/sync-progress-report-to-engagement.handler.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { Injectable } from '@nestjs/common';
12
import { Settings } from 'luxon';
23
import { DateInterval, type UnsecuredDto } from '~/common';
3-
import { EventsHandler, type IEventHandler, ILogger, Logger } from '~/core';
4+
import { ILogger, Logger } from '~/core';
5+
import { OnHook } from '~/core/hooks';
46
import { EngagementService } from '../../engagement';
57
import { type Engagement, engagementRange } from '../../engagement/dto';
68
import {
@@ -15,20 +17,8 @@ import {
1517
type Intervals,
1618
} from './abstract-periodic-report-sync';
1719

18-
type SubscribedEvent =
19-
| EngagementCreatedEvent
20-
| EngagementUpdatedEvent
21-
| ProjectUpdatedEvent;
22-
23-
@EventsHandler(
24-
EngagementCreatedEvent,
25-
EngagementUpdatedEvent,
26-
ProjectUpdatedEvent,
27-
)
28-
export class SyncProgressReportToEngagementDateRange
29-
extends AbstractPeriodicReportSync
30-
implements IEventHandler<SubscribedEvent>
31-
{
20+
@Injectable()
21+
export class SyncProgressReportToEngagementDateRange extends AbstractPeriodicReportSync {
3222
constructor(
3323
periodicReports: PeriodicReportService,
3424
private readonly engagements: EngagementService,
@@ -37,7 +27,15 @@ export class SyncProgressReportToEngagementDateRange
3727
super(periodicReports);
3828
}
3929

40-
async handle(event: SubscribedEvent) {
30+
@OnHook(EngagementCreatedEvent)
31+
@OnHook(EngagementUpdatedEvent)
32+
@OnHook(ProjectUpdatedEvent)
33+
async handle(
34+
event:
35+
| EngagementCreatedEvent
36+
| EngagementUpdatedEvent
37+
| ProjectUpdatedEvent,
38+
) {
4139
// Only LanguageEngagements
4240
if (
4341
!(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type PollVoter } from '~/common';
22
import { type Session } from '../session/session.dto';
33

4-
export class CanImpersonateEvent {
4+
export class CanImpersonateHook {
55
constructor(readonly session: Session, readonly allow: PollVoter<boolean>) {}
66
}

src/core/authentication/session/session.manager.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import {
99
ServerException,
1010
UnauthorizedException,
1111
} from '~/common';
12-
import { IEventBus } from '~/core/events';
12+
import { Hooks } from '~/core/hooks';
1313
import { ILogger, Logger } from '~/core/logger';
1414
import { SystemAgentRepository } from '../../../components/user/system-agent.repository';
1515
import { AuthenticationRepository } from '../authentication.repository';
16-
import { CanImpersonateEvent } from '../events/can-impersonate.event';
16+
import { CanImpersonateHook } from '../hooks/can-impersonate.hook';
1717
import { JwtService } from '../jwt.service';
1818
import { NoSessionException } from './no-session.exception';
1919
import { Session } from './session.dto';
@@ -26,7 +26,7 @@ import { SessionHost } from './session.host';
2626
export class SessionManager {
2727
constructor(
2828
private readonly agents: SystemAgentRepository,
29-
private readonly events: IEventBus,
29+
private readonly hooks: Hooks,
3030
private readonly jwt: JwtService,
3131
private readonly sessionHost: SessionHost,
3232
private readonly repo: AuthenticationRepository,
@@ -105,11 +105,11 @@ export class SessionManager {
105105
if (impersonatee) {
106106
const allowImpersonation = new Poll();
107107
await this.sessionHost.withSession(requesterSession, async () => {
108-
const event = new CanImpersonateEvent(
108+
const event = new CanImpersonateHook(
109109
requesterSession,
110110
allowImpersonation,
111111
);
112-
await this.events.publish(event);
112+
await this.hooks.run(event);
113113
});
114114
if (!(allowImpersonation.plurality && !allowImpersonation.vetoed)) {
115115
// Don't expose what the requester is unable to do as this could leak

src/core/core.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Global, Module } from '@nestjs/common';
22
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
33
import { DataLoaderModule } from '@seedcompany/data-loader';
44
import { DiscoveryModule } from '@seedcompany/nest/discovery';
5+
// eslint-disable-next-line @seedcompany/no-restricted-imports
6+
import { HooksModule } from '@seedcompany/nest/hooks';
57
import { EmailModule } from '@seedcompany/nestjs-email';
68
import { AuthenticationModule } from './authentication/authentication.module';
79
import { AwsS3Factory } from './aws-s3.factory';
@@ -38,6 +40,7 @@ import { WaitResolver } from './wait.resolver';
3840
GelModule,
3941
EmailModule.forRootAsync({ useExisting: ConfigService }),
4042
DiscoveryModule,
43+
HooksModule,
4144
GraphqlModule,
4245
EventsModule,
4346
TracingModule,
@@ -65,6 +68,7 @@ import { WaitResolver } from './wait.resolver';
6568
DatabaseModule,
6669
DataLoaderModule,
6770
DiscoveryModule,
71+
HooksModule,
6872
GelModule,
6973
EmailModule,
7074
EventsModule,

src/core/events/constants.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)