npm package: @globaluy/notifications
Description: Notifications API
Author: GlobalUY
Latest version: 1.0.3

<p align="center">
  <a href="https://globaluy.com" target="blank"><img src="https://www.uruguayxxi.gub.uy/uploads/servicio/resize_a2fc4e36abf059107018b40b00bff7a9fa22108c.png.png" width="100" alt="GlobalUY logo" /></a>
</p>

# Description

Notifications API is a notification module to handle email, push, sms and slack messages.

# Installation

```bash
$ npm install @globaluy/notifications
```

## MIGRATION GUIDE

Para los que usábamos la versión de submodulo revisar la [guía de migración](MIGRATION-GUIDE.md) para actualizar a esta librería.

# Post-installation

Notifications API uses TypeORM as ORM. It relies on 3 tables in order to work properly.

- notifications
- notification_logs
- notification_black_list

It works out the box if `synchronize` is turned on. If it is off then there are a couple of options that you can use:

- create the tables manually using the `init.sql` script.
- generate the migrations pointing to the location of the entities of this package.
  ```javascript
    entities: [
        '...',
        './node_modules/@globaluy/notifications/src/entities/**/*.entity{.ts,.js}',
      ],
  ```
- run existing migrations in this package's migration folder.

# How to use it.

Create notifications.config file in config folder of the root project:

```javascript
//see configuration sample below.
export const notifications = () => ({
   return {
    enabled: env.SEND_EMAILS,
    whitelist: env.EMAILS_WHITE_LIST?.split(','),
    maxAttempts: 2,
    sendLimit: 100,
    account: {
      port: Number(env.EMAIL_SMTP_PORT),
      host: String(env.EMAIL_HOST),
      username: String(env.EMAIL_USER),
      password: String(env.EMAIL_PASSWORD),
      alias: env.EMAIL_FROM,
    },
    from: String(env.EMAIL_FROM),
    templates: String(env.EMAIL_TEMPLATES_PATH),
    push: {
      enabled: env.SEND_PUSH,
      credentialJson: env.FIREBASE_CREDENTIAL_JSON,
      parallelLimit: Number(env.FIREBASE_PARALLEL_LIMIT),
    },
    //configurada en Docker compose
    stopCron: Boolean(+process.env.STOP_CRON),
    slack: {
      enabled: env.SEND_SLACK,
      appToken: env.SLACK_APP_TOKEN,
    },
    twilio: {
      enabled: env.SEND_TWILIO,
      accountSid: env.TWILIO_ACCOUNT_SID,
      authToken: env.TWILIO_AUTH_TOKEN,
      from: env.TWILIO_FROM,
    },
  };
});
```

Add the module into the imports of the app moudle.

`import { NotificationsModule } from 'src/common/notifications';`

`NotificationsModule.forRoot(notifications)`

## Default Environment variables

```
SEND_PUSH=1
FIREBASE_CREDENTIAL_JSON=<{Firebase credential json}>
FIREBASE_PARALLEL_LIMIT=3
SEND_EMAILS=1
EMAIL_HOST=<smtp host>
EMAIL_SMPT_PORT=<smtp port>
EMAIL_USER=<email use>
EMAIL_PASSWORD=<email password>
EMAIL_TEMPLATES_PATH='../../../templates/emails'
TWILIO_ACCOUNT_SID=<Twilio account sid>
TWILIO_AUTH_TOKEN=<Twilio auth token>
TWILIO_FROM=<Twilio from number>
SEND_TWILIO=1
SLACK_APP_TOKEN=<Slack app token>
SLACK_ALERTS_CHANNEL_ID=<Slack app channel id>
SEND_SLACK=1
```

## Usage

Set the service as a module's provider

```javascript
...
import {
  NOTIFICATION_SERVICE_TOKEN,
  NotificationsService,
} from '@globaluy/notifications';

@Module({
  providers: [
    ...
    {
      provide: NOTIFICATION_SERVICE_TOKEN,
      useClass: NotificationsService,
    },
  ],
  imports: [],
  exports: [...],
})
export class Module {}
```

Import it

```javascript
import { NotificationsService } from "@globaluy/notifications";
```

Inject NotificationsService dependency.

```javascript
constructor(
    private notificationsService: NotificationsService,
    ...
  ) {}
```

Create notification message and invoke create or createAndSendImmediately.

```javascript
const notification = {
  subject: this.options.mailNewUserSubject,
  to: user.email,
  template: this.options.mailNewUserTemplate,
  context: JSON.stringify({
    fullName: `${user.firstName} ${user.lastName}`,
    email: user.email,
    url,
    currentYear: new Date().getFullYear(),
    urlLogo: `${this.options.publicAssets}/${this.options.logoName}`,
  }),
};
return this.notificationsService.createAndSendImmediately(notification);
```

## SLACK

### Sample message

```javascript
const message = {
  channelId: "<channel id>",
  title: "Cars Database Appointment Service",
  description: "esto es una prueba",
  moreInfo: "y esto es mas info.",
  type: NotificationAlertType.WARN,
  values: {
    Cause: "Cannot create appointment",
    StatusCode: "BAD REQUEST",
  },
};
```

### slack settings

A bot needs to be created, and from there we could get the token value
The bot needs to be added to the channel we pretend to send messages to.
We get channel id from the channel info modal in slack

## NOTIFICATION KINDS

```javascript
export enum NotificationKind {
  EMAIL = 'email',
  PUSH = 'push',
  PUSH_TOKEN = 'push-to-token',
  SLACK = 'slack',
  SMS = 'sms',
}
```

### Notifications samples.

```javascript
const mailNotificationToSend = {
  to: "<destination email>",
  subject: "test",
  template: "default",
  context: JSON.stringify({ body: "nuevo sms desde app" }),
};
const slackNotificationToSend = {
  to: "<channel id>",
  subject: "test",
  template: "default",
  kind: NotificationKind.SLACK,
  context: JSON.stringify({
    title: "nuevo slack desde app",
    description: "description",
    moreInfo: "y esto es mas info.",
    type: NotificationAlertType.WARN,
    values: {
      Cause: "Cannot create appointment",
      StatusCode: "BAD REQUEST",
    },
  }),
};

const smsNotificationToSend = {
  to: "<phone number>",
  kind: NotificationKind.SMS,
  context: JSON.stringify({ body: "nuevo sms desde app" }),
};
```

## NOTIFICATION SERVICE INTERFACE

```javascript
export interface INotificationsService {
  findOne(options: any): Promise<NotificationDto>;
  findAll(options: any): Promise<NotificationDto[]>;
  findAllAndCount(options: any): Promise<[NotificationDto[], number]>;
  create(notification: DeepPartial<NotificationDto>): Promise<NotificationDto>;
  createAndSendImmediately(
    notification: DeepPartial<NotificationDto>,
  ): Promise<NotificationDto>;
  update(id: number, notification: DeepPartial<NotificationDto>);
  delete(id: number);
  executeScheduler();
}
```