Skip to content

Commit

Permalink
Merge pull request #104 from alkem-io/develop
Browse files Browse the repository at this point in the history
Release: Refactored notifications builders
  • Loading branch information
valentinyanakiev authored Apr 8, 2022
2 parents 9e6e201 + 5173a4f commit be0df34
Show file tree
Hide file tree
Showing 63 changed files with 2,214 additions and 2,429 deletions.
11 changes: 11 additions & 0 deletions notifications.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,14 @@ recipients:
- rule:
type: HUB_MEMBER
resource_id: <hubID>
community_review_submitted:
- name: admin
rules:
- rule:
type: CHALLENGE_ADMIN
resource_id: <challengeID>
- name: reviewer
rules:
- rule:
type: USER_SELF_MANAGEMENT
resource_id: <reviewerID>
2,753 changes: 1,003 additions & 1,750 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "alkemio-notifications",
"version": "0.5.1",
"version": "0.5.3",
"description": "Alkemio notifications service",
"author": "Alkemio Foundation",
"private": false,
Expand Down Expand Up @@ -34,7 +34,7 @@
"validate-connection": "ts-node src/utils/validate-connection.ts"
},
"dependencies": {
"@alkemio/client-lib": "^0.13.0",
"@alkemio/client-lib": "^0.13.1",
"@nestjs/axios": "^0.0.1",
"@nestjs/common": "^8.0.5",
"@nestjs/config": "^1.0.1",
Expand Down
39 changes: 29 additions & 10 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ import { Controller, Inject, LoggerService } from '@nestjs/common';
import { Ctx, EventPattern, Payload, RmqContext } from '@nestjs/microservices';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { Channel, Message } from 'amqplib';
import { NotificationStatus } from 'notifme-sdk';
import {
ALKEMIO_CLIENT_ADAPTER,
COMMUNICATION_DISCUSSION_CREATED,
COMMUNICATION_UPDATE_SENT,
COMMUNITY_APPLICATION_CREATED,
COMMUNITY_CONTEXT_REVIEW_SUBMITTED,
LogContext,
USER_REGISTERED,
} from './common';
import { IFeatureFlagProvider } from '@core/contracts';
import { ApplicationCreatedEventPayload } from '@src/types/application.created.event.payload';
import { UserRegistrationEventPayload } from './types';
import { CommunicationUpdateEventPayload } from './types/communication.update.event.payload';
import { CommunicationDiscussionCreatedEventPayload } from './types/communication.discussion.created.event.payload';
import {
ApplicationCreatedEventPayload,
CommunicationUpdateEventPayload,
CommunicationDiscussionCreatedEventPayload,
CommunityContextReviewSubmittedPayload,
UserRegistrationEventPayload,
} from '@common/dto';
import { NotificationService } from './services/domain/notification/notification.service';

@Controller()
Expand Down Expand Up @@ -88,11 +93,25 @@ export class AppController {
);
}

@EventPattern(COMMUNITY_CONTEXT_REVIEW_SUBMITTED)
async sendCommunityContextFeedbackNotifications(
@Payload() eventPayload: CommunityContextReviewSubmittedPayload,
@Ctx() context: RmqContext
) {
this.sendNotifications(
eventPayload,
context,
this.notificationService.sendCommunityContextFeedbackNotification(
eventPayload
),
COMMUNITY_CONTEXT_REVIEW_SUBMITTED
);
}

private async sendNotifications(
@Payload() eventPayload: any,
@Payload() eventPayload: Record<string, unknown>,
@Ctx() context: RmqContext,
// notificationBuilder: any,
sendNotificationsImpl: any,
sentNotifications: Promise<PromiseSettledResult<NotificationStatus>[]>,
eventName: string
) {
this.logger.verbose?.(
Expand All @@ -109,8 +128,8 @@ export class AppController {
}

// https://www.squaremobius.net/amqp.node/channel_api.html#channel_nack
sendNotificationsImpl
.then((x: any[]) => {
sentNotifications
.then(x => {
const nacked = x.filter(
(y: { status: string }) => y.status === 'rejected'
);
Expand All @@ -136,7 +155,7 @@ export class AppController {
}
}
})
.catch((err: any) => {
.catch(err => {
// if there is an unhandled bug in the flow, we reject the message but we make sure the message is
// not discarded so we provide 'true' to requeue parameter
// channel.reject(originalMsg, true);
Expand Down
14 changes: 10 additions & 4 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import { HttpExceptionsFilter } from './core';
import {
AlkemioClientAdapterModule,
ApplicationCreatedNotificationBuilder,
NotificationRecipientsAdapterModule,
} from '@src/services';
import { AlkemioClientModule, NotifmeModule } from '@src/services/external';
import { NotificationRecipientsAdapterModule } from './services/application/notification-recipients-adapter/notification.recipients.adapter.module';
import { UserRegisteredNotificationBuilder } from './services/domain/builders/user-registered/user.registered.notification.builder';
import { CommunicationUpdateNotificationBuilder } from './services/domain/builders/communication-updated/communication.updated.notification.builder';
import { CommunicationDiscussionCreatedNotificationBuilder } from './services/domain/builders/communication-discussion-created/communication.discussion.created.notification.builder';
import {
CommunicationDiscussionCreatedNotificationBuilder,
CommunicationUpdateNotificationBuilder,
CommunityContextReviewSubmittedNotificationBuilder,
UserRegisteredNotificationBuilder,
} from './services/domain/builders';
import { AlkemioUrlGeneratorModule } from './services/application/alkemio-url-generator';
import { NotificationService } from './services/domain/notification/notification.service';
import { NotificationBuilderFactoryProvider } from './services/application/notification-builder';

@Module({
imports: [
Expand All @@ -39,10 +43,12 @@ import { NotificationService } from './services/domain/notification/notification
provide: APP_FILTER,
useClass: HttpExceptionsFilter,
},
NotificationBuilderFactoryProvider,
ApplicationCreatedNotificationBuilder,
UserRegisteredNotificationBuilder,
CommunicationUpdateNotificationBuilder,
CommunicationDiscussionCreatedNotificationBuilder,
CommunityContextReviewSubmittedNotificationBuilder,
NotificationService,
],
controllers: [AppController],
Expand Down
2 changes: 2 additions & 0 deletions src/common/constants/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export const USER_REGISTERED = 'userRegistered';
export const COMMUNICATION_UPDATE_SENT = 'communicationUpdateSent';
export const COMMUNICATION_DISCUSSION_CREATED =
'communicationDiscussionCreated';
export const COMMUNITY_CONTEXT_REVIEW_SUBMITTED =
'communityContextReviewSubmitted';
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { HubPayload } from './hub.payload';

export enum CommunityType {
HUB = 'hub',
CHALLENGE = 'challenge',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { CommunityType } from './application.created.event.payload';
import { HubPayload } from './hub.payload';

export type CommunicationDiscussionCreatedEventPayload = {
discussion: {
id: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HubPayload } from './hub.payload';
import { CommunityType } from './application.created.event.payload';

export type CommunicationUpdateEventPayload = {
update: {
Expand Down
12 changes: 12 additions & 0 deletions src/common/dto/community.context.review.submitted.payload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type CommunityContextReviewSubmittedPayload = {
userId: string;
challengeId: string;
community: { name: string };
questions: FeedbackQuestions[];
};

export type FeedbackQuestions = {
name: string;
value: string;
sortOrder: number;
};
File renamed without changes.
6 changes: 6 additions & 0 deletions src/common/dto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './application.created.event.payload';
export * from './communication.discussion.created.event.payload';
export * from './communication.update.event.payload';
export * from './community.context.review.submitted.payload';
export * from './user.registration.event.payload';
export * from './hub.payload';
5 changes: 5 additions & 0 deletions src/common/enums/alkemio.error.status.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export enum AlkemioErrorStatus {
NOT_SUPPORTED = 'NOT_SUPPORTED',
TEMPLATE_NOT_PROVIDED = 'TEMPLATE_NOT_PROVIDED',
PAYLOAD_NOT_PROVIDED = 'PAYLOAD_BUILDER_NOT_PROVIDED',
TEMPLATE_BUILDER_NOT_PROVIDED = 'TEMPLATE_BUILDER_NOT_PROVIDED',
ROLES_NOT_PROVIDED = 'ROLES_NOT_PROVIDED',
RULES_SET_NOT_FOUND = 'RULE_SET_NOT_FOUND',
}
2 changes: 2 additions & 0 deletions src/common/enums/email.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export enum EmailTemplate {
COMMUNICATION_DISCUSSION_CREATED_MEMBER = 'communication.discussion.created.member',
COMMUNICATION_UPDATE_ADMIN = 'communication.update.admin',
COMMUNICATION_UPDATE_MEMBER = 'communication.update.member',
COMMUNITY_REVIEW_SUBMITTED_ADMIN = 'community.review.submitted.admin',
COMMUNITY_REVIEW_SUBMITTED_REVIEWER = 'community.review.submitted.reviewer',
}
1 change: 1 addition & 0 deletions src/common/exceptions/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './not.supported.exception';
export * from './base.exception';
export * from './notification-builder';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from '../base.exception';

export class EventPayloadNotProvidedException extends BaseException {
constructor(error: string, context = LogContext.NOTIFICATIONS) {
super(error, context, AlkemioErrorStatus.PAYLOAD_NOT_PROVIDED);
}
}
5 changes: 5 additions & 0 deletions src/common/exceptions/notification-builder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './template.not.provided.exception';
export * from './template.builder.fn.not.provided.exception';
export * from './event.payload.not.provided.exception';
export * from './roles.not.provided.exception';
export * from './rule.set.not.found.exception';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from '../base.exception';

export class RolesNotProvidedException extends BaseException {
constructor(error: string, context = LogContext.NOTIFICATIONS) {
super(error, context, AlkemioErrorStatus.ROLES_NOT_PROVIDED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from '../base.exception';

export class RuleSetNotFoundException extends BaseException {
constructor(error: string, context = LogContext.NOTIFICATIONS) {
super(error, context, AlkemioErrorStatus.RULES_SET_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from '../base.exception';

export class TemplateBuilderFnNotProvidedException extends BaseException {
constructor(error: string, context = LogContext.NOTIFICATIONS) {
super(error, context, AlkemioErrorStatus.TEMPLATE_BUILDER_NOT_PROVIDED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LogContext, AlkemioErrorStatus } from '@common/enums';
import { BaseException } from '../base.exception';

export class TemplateNotProvidedException extends BaseException {
constructor(error: string, context = LogContext.NOTIFICATIONS) {
super(error, context, AlkemioErrorStatus.TEMPLATE_NOT_PROVIDED);
}
}
1 change: 1 addition & 0 deletions src/core/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './notified.users.provider.interface';
export * from './feature.flag.provider.interface';
export * from './notification.recipient.template.provider.interface';
export * from './notification.builder.interface';
5 changes: 5 additions & 0 deletions src/core/contracts/notification.builder.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { NotificationTemplateType } from '@src/types';

export interface INotificationBuilder {
build(payload: Record<string, unknown>): Promise<NotificationTemplateType[]>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuthorizationCredential } from '@alkemio/client-lib';
import { CredentialCriteria } from '../models/credential.criteria';
import { CredentialCriterion } from '../models/credential.criterion';

export type TemplateRule = {
rule: {
Expand All @@ -18,14 +18,15 @@ export type TemplateConfig = {
user_registered?: TemplateRuleSet[];
communication_update_sent?: TemplateRuleSet[];
communication_discussion_created?: TemplateRuleSet[];
community_review_submitted?: TemplateRuleSet[];
};

export interface INotificationRecipientTemplateProvider {
getTemplate(): TemplateConfig;

getCredentialCriterias(
lookupMap: Map<string, string>,
templateRuleSets: TemplateRuleSet[] | undefined,
roleName: string
): CredentialCriteria[];
getCredentialCriteria(
roleName: string,
lookupMap?: Map<string, string>,
templateRuleSets?: TemplateRuleSet[]
): CredentialCriterion[];
}
4 changes: 2 additions & 2 deletions src/core/contracts/notified.users.provider.interface.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { User } from '../models';
import { CredentialCriteria } from '../models/credential.criteria';
import { CredentialCriterion } from '../models/credential.criterion';
import { IFeatureFlagProvider } from './feature.flag.provider.interface';

export interface INotifiedUsersProvider extends IFeatureFlagProvider {
getUser(userID: string): Promise<User>;
getUniqueUsersMatchingCredentialCriteria(
credentialCriterias: CredentialCriteria[]
credentialCriteria: CredentialCriterion[]
): Promise<User[]>;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AuthorizationCredential } from '@alkemio/client-lib';

export type CredentialCriteria = {
export type CredentialCriterion = {
type: AuthorizationCredential;
resourceID?: string;
};
2 changes: 1 addition & 1 deletion src/core/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './user';
export * from './credential.criteria';
export * from './credential.criterion';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Inject, Injectable, LoggerService } from '@nestjs/common';
import { AlkemioClient } from '@alkemio/client-lib';
import { ALKEMIO_CLIENT_PROVIDER, LogContext } from '@src/common';
import { IFeatureFlagProvider } from '@core/contracts';
import { CredentialCriteria, User } from '@core/models';
import { CredentialCriterion, User } from '@core/models';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';

@Injectable()
Expand Down Expand Up @@ -33,7 +33,7 @@ export class AlkemioClientAdapter implements IFeatureFlagProvider {
}

async getUsersMatchingCredentialCriteria(
credentialCriteria: CredentialCriteria
credentialCriteria: CredentialCriterion
): Promise<User[]> {
let resourceID: string | undefined = undefined;
if (credentialCriteria.resourceID)
Expand All @@ -49,12 +49,12 @@ export class AlkemioClientAdapter implements IFeatureFlagProvider {
}

async getUniqueUsersMatchingCredentialCriteria(
credentialCriterias: CredentialCriteria[]
credentialCriteria: CredentialCriterion[]
): Promise<User[]> {
const users: User[] = [];
for (const criteria of credentialCriterias) {
for (const criterion of credentialCriteria) {
const matchedUsers = await this.getUsersMatchingCredentialCriteria(
criteria
criterion
);
users.push(...matchedUsers);
}
Expand Down
5 changes: 5 additions & 0 deletions src/services/application/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './notification-builder';
export * from './alkemio-client-adapter';
export * from './alkemio-url-generator';
export * from './notification-recipients-adapter';
export * from './template-to-credential-mapper';
2 changes: 2 additions & 0 deletions src/services/application/notification-builder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './notification.builder';
export * from './notification.builder.factory.provider';
Loading

0 comments on commit be0df34

Please sign in to comment.