Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: Vitaliy/notifications backend #128

Open
wants to merge 11 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions runtime/backend/src/common/services/AccountsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
AccountModel,
AccountQuery,
} from "../models/AccountSchema";
import { EventEmitter2 } from "@nestjs/event-emitter";

// configuration resources
import { DappConfig, NetworkConfig } from "../models";
Expand Down Expand Up @@ -49,6 +50,7 @@ export class AccountsService {
AccountDocument,
AccountModel
>,
private readonly emitter: EventEmitter2,
) {}

/**
Expand Down Expand Up @@ -183,6 +185,16 @@ export class AccountsService {
// create a random referral code
const referralCode = AccountsService.getRandomReferralCode();

// create notification for newly created user
this.emitter.emit("notifier.users.notify", {
address: payload.address,
subjectType: "general",
title: "Welcome to Elevate!",
description:
"Welcome to Elevate! Please, integrate your account with provider.",
shortDescription: "Thanks for joining!",
});

// store the authenticated address in `accounts`
return await this.createOrUpdate(accountQuery, {
referralCode,
Expand Down
2 changes: 2 additions & 0 deletions runtime/backend/src/notifier/NotifierModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { AbstractAppModule } from "../common/modules/AbstractAppModule";
// notifier scope
import { EmailNotifierModule } from "./modules/EmailNotifierModule";
import { NotifierFactoryModule } from "./modules/NotifierFactoryModule";
import { UserNotifierModule } from "./modules/UserNotifierModule";
import { AlertsModule } from "./modules/AlertsModule";

/**
Expand Down Expand Up @@ -44,6 +45,7 @@ import { AlertsModule } from "./modules/AlertsModule";
EmailNotifierModule,
NotifierFactoryModule,
AlertsModule,
UserNotifierModule,
],
})
export class NotifierModule extends AbstractAppModule {}
145 changes: 145 additions & 0 deletions runtime/backend/src/notifier/models/UserNotificationDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* This file is part of dHealth dApps Framework shared under LGPL-3.0
* Copyright (C) 2022-present dHealth Network, All rights reserved.
*
* @package dHealth dApps Framework
* @subpackage Backend
* @author dHealth Network <[email protected]>
* @license LGPL-3.0
*/
// external dependencies
import { ApiProperty } from "@nestjs/swagger";

// internal dependencies
import { BaseDTO } from "../../common/models/BaseDTO";

/**
* @class UserNotificationDTO
* @description A DTO class that consists of notification properties
*
* @since v0.3.0
*/
export class UserNotificationDTO extends BaseDTO {
/**
* The Address of this account on dHealth Network. The
* account's **address** typically refers to a human-readable
* series of 39 characters, starting either with a `T`, for
* TESTNET addresses, or with a `N`, for MAINNET addresses.
*
* @example `"NDAPPH6ZGD4D6LBWFLGFZUT2KQ5OLBLU32K3HNY"`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example: "NDAPPH6ZGD4D6LBWFLGFZUT2KQ5OLBLU32K3HNY",
description: "The Address of the linked account on dHealth Network",
})
public address?: string; // if no address - notification is for everyone

/**
* Subject id field, represents identifier
* of subject which was received. Can be asset.id or activity.id
*
* @example `"6377bb780a56699ae5ca4e4c"`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example: "6377bb780a56699ae5ca4e4c",
description: "Id of the asset or of activity",
})
public subjectId?: string; // if no subjectId - notification is for general purposes, e.g. strava integrated notification, welcome notification

/**
* Subject type field represents notification
* type assets or activities related. Can have
* "general" type if notification related to general events
* e.g. Registration, strava integration, etc.
*
* @example `"assets"`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example: "assets",
description: "Type of the notification",
})
public subjectType: "assets" | "activities" | "general";

/**
* Title of the notification which
* describes notification in 2-3 words.
*
* @example `Successfully integrated strava`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example: "Successfully integrated strava",
description: "Title of the notification",
})
public title: string;

/**
* Description of the notification
* which explains notification in details.
*
* @example `You successfully integrated your strava account to your elevate profile, congrats!`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example:
"You successfully integrated your strava account to your elevate profile, congrats!",
description: "Full description of the notification",
})
public description: string;

/**
* Short description of the notifications
* which should be displayed in notifications *preview*.
*
* @example `You successfully strava account`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string",
example: "You successfully strava account",
description: "Short description of the notification",
})
public shortDescription: string;

/**
* Property which represents date when user got read notification.
*
* @example `2022-11-18T17:06:00.330+00:00`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string | number",
example: "2022-11-18T17:06:00.330+00:00",
description: "Date when notification has been read by user.",
})
public readAt?: string | number;

/**
* Property which represents date when notification has been created.
*
* @example `2022-11-18T17:06:00.330+00:00`
* @access public
* @var {string}
*/
@ApiProperty({
type: "string | number",
example: "2022-11-18T17:06:00.330+00:00",
description: "Date when notification has been created.",
})
public createdAt: string | number;
}
167 changes: 167 additions & 0 deletions runtime/backend/src/notifier/models/UserNotificationSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/**
* This file is part of dHealth dApps Framework shared under LGPL-3.0
* Copyright (C) 2022-present dHealth Network, All rights reserved.
*
* @package dHealth dApps Framework
* @subpackage Backend
* @author dHealth Network <[email protected]>
* @license LGPL-3.0
*/

// external dependencies
import { Schema, Prop, SchemaFactory } from "@nestjs/mongoose";
import { Model } from "mongoose";

// internal dependencies
import { Transferable } from "../../common/concerns/Transferable";
import { UserNotificationDTO } from "./UserNotificationDTO";
import { Documentable } from "../../common/concerns/Documentable";
import { Queryable, QueryParameters } from "../../common/concerns/Queryable";

@Schema({
timestamps: true,
})
export class Notification implements Transferable<UserNotificationDTO> {
/**
* This field contains the *mongo collection name* for entries
* that are stored using {@link ActivityDocument} or the model
* {@link ActivityModel}.
* <br /><br />
* Note that this field **is not** part of document properties
* and used only internally to perform queries that refer to
* an individual collection name, e.g. `$unionWith`.
*
* @access public
* @var {string}
*/
public collectionName = "notifications";

/**
* The account's **address**. An address typically refers to a
* human-readable series of 39 characters, starting either with
* a `T`, for TESTNET addresses, or with a `N`, for MAINNET addresses.
* <br /><br />
* This field is **required** and *indexed*.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: false, index: true })
public readonly address: string;

/**
* Subject id field, represents identifier
* of subject which was received. Can be asset.id or activity.id
* If !subjectId -> notification is for general purpose e.g. Register, strava integration, etc.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: false })
public readonly subjectId: string;

/**
* Subject id field, represents identifier
* of subject which was received. Can be asset.id or activity.id
* If !subjectId -> notification is for general purpose e.g. Register, strava integration, etc.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: true })
public readonly subjectType: "assets" | "activities" | "general";

/**
* Title of the notification which
* describes notification in 2-3 words.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: true })
public readonly title: string;

/**
* Description of the notification
* which explains notification in details.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: true })
public readonly description: string;

/**
* Short description of the notifications
* which should be displayed in notifications *preview*.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: true })
public readonly shortDescription: string;

/**
* Property which represents date when user got read notification.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: false })
public readonly readAt?: string;

/**
* Property which represents date when notification has been created.
*
* @access public
* @readonly
* @var {string}
*/
@Prop({ required: true })
public readonly createdAt: string;

public static fillDTO(
doc: UserNotificationDocument,
dto: UserNotificationDTO,
): UserNotificationDTO {
dto.address = doc.address;
dto.subjectId = doc.subjectId;
dto.subjectType = doc.subjectType;
dto.title = doc.title;
dto.description = doc.description;
dto.shortDescription = doc.shortDescription;
dto.readAt = doc.readAt;
dto.createdAt = doc.createdAt;
return dto;
}
}

export type UserNotificationDocument = Notification & Documentable;

export class UserNotificationModel extends Model<Notification> {}

export class UserNotificationQuery extends Queryable<UserNotificationDocument> {
/**
* Copy constructor for pageable queries in `notifications` collection.
*
* @see Queryable
* @param {AccountIntegrationDocument|undefined} document The *document* instance (defaults to `undefined`) (optional).
* @param {QueryParameters|undefined} queryParameters The query parameters including as defined in {@link QueryParameters} (optional).
*/
public constructor(
document?: UserNotificationDocument,
queryParams: QueryParameters = undefined,
) {
super(document, queryParams);
}
}

export const UserNotificationSchema =
SchemaFactory.createForClass(Notification);
6 changes: 6 additions & 0 deletions runtime/backend/src/notifier/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ export * from "./TransportConfig";
export * from "./Notifier";
export * from "./NotifierType";
export * from "./ReportNotifierStateData";

// schemas
export * from "./UserNotificationSchema";

// DTO
export * from "./UserNotificationDTO";
Loading