Notifications engine
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
config
core
db
dbapi
handlers
migrations
utils
.gitignore
.travis.yml
Dockerfile
Gopkg.lock
Gopkg.toml
LICENSE.txt
Makefile
README.md
docker-compose.yaml
main.go
urls.go

README.md

GoDoc Build Status Coverage Status Gitter

Khabar

Notifications engine.

It means

the latest information; news.

google it

Table of contents

Concept and idea

How does it work?

Development

$ go get github.com/codegangsta/gin
$ go get github.com/tools/godep
  • gin is used to to automatically compile files while you are developing
  • godep is used to manage dependencies

Then run

$ mkdir -p $GOPATH/src/github.com/bulletind
$ cd $GOPATH/src/github.com/bulletind
$ git clone https://github.com/bulletind/khabar.git # or your fork
$ cd khabar
$ DEBUG=* go get && go install && gin -p 8911 -i # or make dev

Now you should be able to access the below API's on port 8911.

MongoDB config is stored in config/conf.go. Same goes for TranslationDirectory. Or provide env vars MONGODB_URL and TRANSLATION_DIRECTORY.

After you make the changes (if you import any new deps), don't forget to run

$ godep save ./... # or make godep

Sanity checks

$ make vet    # https://godoc.org/golang.org/x/tools/cmd/vet
$ make lint   # https://github.com/golang/lint
$ make test

Usage

$ go get github.com/bulletind/khabar
$ khabar

API

  1. Preferences

  2. List all preferences of user or org
```
GET /topics
```

Query params:

- `org`: organization id
- `user`: user id

If org and user are not sent in query params, then it will send global preferences.

If org is sent and user is not, then it will send org preferences.

If org and user are both sent, then it will send user preferences.

Response:
```js
[
  {
    "_id": "",
    "created_on": 1425547531188,
    "updated_on": 1425879125700,
    "user": "",
    "org": "",
    "app_name": "",
    "channels": [
      "",
      ""
    ],
    "ident": ""
  }
]
```
  1. Set an user preference
```
POST /topics/:ident/channels/:channel
```

Query params:

- `org`: (required) organization id
- `user`: (required) user id
  1. Unset an user preference
```
DELETE /topics/:ident/channels/:channel
```

Query params:

- `org`: (required) organization id
- `user`: (required) user id
  1. Set an org preference
```
POST /topics/:type/:ident/channels/:channel
```

`:type` here is either `defaults` or `locked`

Query params:

- `org`: (required) organization id
  1. Unset an org preference
```
DELETE /topics/:type/:ident/channels/:channel
```

`:type` here is either `defaults` or `locked`

Query params:

- `org`: (required) organization id
  1. Notifications

  2. List all notifications
```
GET /notifications
```

Query params:

- `user`: user id
- `org`: organization id

Response:
```js
[
  {
    org: "",
    user: "",
    destination_uri: "",
    text: "",
    topic: "",
    destination_uri: "",
    is_read:false,
    created_on: <milliseconds_since_epoch>
   },
   // and so on...
]
```

This can be polled periodically
  1. Mark a single notification as read
```
PUT /notification/:_id
```

Request Body:
```json
{
  "destination_uri": "http://link-to-entity",
  "text": "Notification text",
  "topic": "Notification topic"
}
```

- `destination_uri`: (required) Link to relevant entity. (i.e action, incident)
- `text`: (required) Notification text (long text)
- `topic`: (required) Notification topic (short text)
  1. Mark all unread notifications as read
```
PUT /notifications
```

Request Body:
```json
{
  "org": "123",
  "user": "456"
}
```

- `org`: (required) org id
- `user`: (required) user id
- `app_name`: (optional) name of the app or category
  1. Get notification stats
```
GET /notifications/stats
```

Query params:

- `user`: (required) user id
- `org`: (required) organization id

Response:
```
{
  "last_seen": "2015-08-03T14:26:05.860Z",
  "total_count": 37,
  "unread_count": 0,
  "total_unread": 32
}
```
  1. Update last seen time stamp
```
PUT /notifications/stats
```

Query params:

- `user`: (required) user id
- `org`: (required) organization id
  1. Send notification
```
POST /notifications?topic=text
```

Request Body:
```js
{
  "created_by" : "5486e02870a0d30200bdcfd3",
  "org" : "5486d3d986ba633a207682b6",
  "app_name" : "myapp", // <- this is the category
  "topic" : "log_incoming",
  "user" : "5486e02870a0d30200bdcfe0",
  "destination_uri" : "http://...",
  "device_tokens": [{ "token": "5486d3d986ba633a207682b6", "type": "ios", "app_name": "myapp" }],
  "attachments": [
    { "url": "http://lorempixel.com/128/64/animals?w=128&h=128", "name": "nicename.png", "is_public": true, "thumbnail_url":   "http://lorempixel.com/128/64/animals?w=128&h=128", "type": "image/jpeg" },
    { "url": "http://private.com/5486d3d986ba633a207682b6", "name": "nicename.jpeg", "is_public": false }
  ],
  "context" : {
    "Organization" : "5486d3d986ba633a207682b6",
    "sender" : "org name",
    "fullname" : "John hopkins",
    "logger" : "Elvis",
    "refnumber" : "IL2958",
    "Collection" : "collection_name",
    "Id" : "554caa744aca430a00de5324",
    "User" : "5486e02870a0d30200bdcfe0",
    "destination_uri" : "http://...",
    "email" : "john.hopkins@email",
    "severity" : "low",
    "subject" : "New log"
  },
  settings: {
    header: '<td><div>My nice header</div></td>', // not required
    logo: 'path_to_logo', // not required
    footer: 'nice story', // not required
    help: 'nice story', // not required
    administrator: { // required!
      name: 'John Doe',
      email: 'name@domain.com'
    },
    sender: { // not required
      name: 'John Doe',
      email: 'name@domain.com'
    }
  },
  "entity" : "554caa744aca430a00de5324"
}
```

Query params:

- `topic`: Text that is used for sending notification (short text)

Some general conventions:

  • For all of the above request you must pass at least one of the org or user or both

  • context.email is used for sending out emails

  • device_tokens are used to send out push notifications, device_token.app_name needs to match app_name

  • attachments are attached to the email.

  • For all the listings, you get a status code of 200

  • When you create a resource you get a status code of 201

  • When you modify/delete a resource you get a status code of 204

  • Response for creation of an entity

    {
      "body": "[ID of entity created]",
      "message": "Created",
      "status": 201
    }
  • Response for modifying/deleting an entity

    {
      "body": "",
      "message": "NoContent",
      "status": 204
    }

Environment variables

We use environment variables to fetch the keys and secrets.

Push notifications

We support both Parse and AWS SNS to send out push notifications. As long as env variable SNS_KEY is not there push notifications are sent out using Parse.

Push notifications (PARSE)

We use parse to send push notifications. When you are sending out a notification using the POST /notifications api call, it looks for certain environment variables. These env variables are based on the categories (app_names) you are using in the topics_available collection.

For example: You have an event (ident) log_incoming configured for the category (app_name) myapp in the topics_available collection. Now, when you make a call to POST /notifications, it looks for PARSE_myapp_API_KEY and PARSE_myapp_APP_ID enviroment variables and uses them to send the push notifications.

You can set them by doing

$ export PARSE_myapp_API_KEY=***
$ export PARSE_myapp_APP_ID=***

Push notifications (SNS)

We use sns to send push notifications. For setup see README of https://github.com/changer/pushnotification.

When you are sending out a notification using the POST /notifications api call, it looks for certain environment variables. Besides base AWS variables key, secret and region there are env variables are based on the categories (app_names) you are using in the topics_available collection. You will need one per mobile platform (ios|android|windows).

For example: You have an event (ident) log_incoming configured for the category (app_name) myapp in the topics_available collection. Now, when you make a call to POST /notifications, it looks for SNS_ANDROID_myapp and SNS_IOS_myapp enviroment variables and uses them to send the push notifications.

You can set them by doing

$ export SNS_KEY=***
$ export SNS_SECRET=***
$ export SNS_REGION=***
$ export SNS_GCM_myapp=***
$ export SNS_APNS_myapp=***
$ export SNS_APNSSANDBOX_myapp=***

Email notifications

When sending emails, some magic is involved. The supplied translations will be searched for a base email base.tmpl template in directory email. This template needs to have a Subject and a Content section. Besides that a basic translation file <locale>_email.json will be loaded so footers and other 'static' content can be provided to the base template. All styles defined in the styles section in the base template will be applied to all relevant elements, so no inline styling is needed.

When no topic entry is available the directory <locale>_email will be searched for the topic template <topic>.tmpl. More complex logic can be used within the template like loops etc.. See for more info the html/template package.

All attachments are attached to the email. When the url is public, the file will be downloaded. When the url is private, the file is downloaded using the provided settings for the media server.

You can configure the email notifications by setting the env variables. Except for SMTP_FROM_NAME all keys are required. SMTP_FROM_NAME will be used as sender name. When a sender is provided in the context, it will be combined to SMTP_FROM_NAME (sender).

$ export SMTP_HOSTNAME=***
$ export SMTP_USERNAME=***
$ export SMTP_PASSWORD=***
$ export SMTP_PORT=***
$ export SMTP_FROM_EMAIL=***
$ export SMTP_FROM_NAME=***
$ export MEDIA_HOST=***
$ export MEDIA_PUBLIC_KEY=***
$ export MEDIA_SECRET_KEY=***