Skip to content

Commit

Permalink
Merge pull request #164 from CirclesUBI/news-activity-log
Browse files Browse the repository at this point in the history
News activity log
  • Loading branch information
llunaCreixent authored Mar 28, 2023
2 parents a4f4c00 + 2418365 commit 3841143
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 17 deletions.
49 changes: 43 additions & 6 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Returns stored transfer meta data including the payment note. This data is only
- `403` Verification failed or not allowed to read data
- `404` Transaction hash not found

### Get entry by username
### Get user entry by username

Get the users entry including its `safeAddress`.

Expand All @@ -174,7 +174,7 @@ Get the users entry including its `safeAddress`.

- `404` Not found

### Search database by usernames
### Search users database by usernames

Find a user in the database.

Expand Down Expand Up @@ -206,7 +206,7 @@ Find a user in the database.

When no user was found an empty response will be returned.

### Get multiple entries by username / address
### Get multiple user entries by username / address

Resolve multiple usernames (via `username[]`) and/or Safe addresses (via `address[]`) in a batch.

Expand Down Expand Up @@ -263,7 +263,7 @@ Do a dry-run to check if `email` and `username` fields are valid before creating
- `400` Parameters missing or malformed
- `409` Entry already exists

### Create new entry
### Create new user entry

**Request:**

Expand Down Expand Up @@ -307,7 +307,7 @@ Create a new entry in the database, connecting a `username` with a `safeAddress`
- `403` Verification failed
- `409` Entry already exists

### Update entry
### Update user entry

**Request:**

Expand Down Expand Up @@ -349,7 +349,7 @@ Update (or create) an entry in the database, connecting a `username` with a `saf
- `403` Verification failed
- `409` Entry already exists

### Get email
### Get user email

**Request:**

Expand Down Expand Up @@ -379,3 +379,40 @@ Get the email from the entry of the `safeAddress` in the database.
- `400` Parameters missing or malformed
- `403` Verification failed
- `404` User entry not found

### Search news database by date

Resolves multiple news items starting from newest item in the database, via:
- `isActive` specifies whether only active or only inactive items should be returned (default true)
- `afterDate` sets a past limit in time before which no news items are included. The response will include news on the exact "afterDate"-date. (default no limit)
- `limit` the maximum number of items returned
- `offset` skips that number of the filtered latest items

**Request:**

`GET /api/news?isActive=<boolean>&afterDate=<Date>&limit=<int>&offset=<int>`

**Response:**

```
{
status: 'ok',
data: [
{
iconId: <int>,
message: {
en: <string>,
},
date: <date>,
},
{
[...]
},
[...]
]
}
```

**Errors:**

When no news were found an empty response will be returned.
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"pg": "^8.8.0",
"pg-copy-streams": "^6.0.4",
"sequelize": "^6.28.0",
"sequelize-cli": "^6.5.2",
"sequelize-cli": "^6.6.0",
"sharp": "^0.31.3",
"web3": "^1.8.1",
"winston": "^3.8.2"
Expand Down
63 changes: 63 additions & 0 deletions src/controllers/news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Op } from 'sequelize';

import News from '../models/news';
import { respondWithSuccess } from '../helpers/responses';

function prepareNewsResult(response) {
return {
iconId: response.iconId,
message: {
en: response.message_en,
},
date: response.date,
isActive: response.isActive,
};
}

async function resolveBatch(req, res, next) {
const { isActive, limit, offset } = req.query;

News.findAll({
where: {
isActive: isActive,
},
order: [['date', 'DESC']],
limit: limit,
offset: offset,
})
.then((response) => {
respondWithSuccess(res, response.map(prepareNewsResult));
})
.catch((err) => {
next(err);
});
}

async function findByDate(req, res, next) {
const { isActive, afterDate, limit, offset } = req.query;

News.findAll({
where: {
isActive: isActive,
date: { [Op.gte]: new Date(afterDate) },
},
order: [['date', 'DESC']],
limit: limit,
offset: offset,
})
.then((response) => {
respondWithSuccess(res, response.map(prepareNewsResult));
})
.catch((err) => {
next(err);
});
}

export default {
findNews: async (req, res, next) => {
if (req.query.afterDate) {
return await findByDate(req, res, next);
}
return await resolveBatch(req, res, next);
},
};
44 changes: 44 additions & 0 deletions src/database/migrations/20230207095851-create-news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('news', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
createdAt: {
type: Sequelize.DATE,
},
updatedAt: {
type: Sequelize.DATE,
},
message_en: {
type: Sequelize.TEXT,
},
date: {
type: Sequelize.DATE,
allowNull: false,
validate: {
notEmpty: true,
},
defaultValue: Sequelize.NOW,
},
iconId: {
type: Sequelize.INTEGER,
allowNull: false,
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: true,
},
});
},

async down(queryInterface) {
await queryInterface.dropTable('news');
},
};
33 changes: 33 additions & 0 deletions src/models/news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Sequelize from 'sequelize';

import db from '../database';

const News = db.define('news', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
message_en: {
type: Sequelize.TEXT,
},
date: {
type: Sequelize.DATE,
allowNull: false,
validate: {
notEmpty: true,
},
defaultValue: Sequelize.NOW,
},
iconId: {
type: Sequelize.INTEGER,
allowNull: false,
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: true,
},
});

export default News;
2 changes: 2 additions & 0 deletions src/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from 'express';
import httpStatus from 'http-status';

import APIError from '../helpers/errors';
import newsRouter from './news';
import transfersRouter from './transfers';
import uploadsRouter from './uploads';
import usersRouter from './users';
Expand All @@ -13,6 +14,7 @@ router.get('/', (req, res) => {
respondWithSuccess(res);
});

router.use('/news', newsRouter);
router.use('/transfers', transfersRouter);
router.use('/uploads', uploadsRouter);
router.use('/users', usersRouter);
Expand Down
11 changes: 11 additions & 0 deletions src/routes/news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import express from 'express';

import newsController from '../controllers/news';
import newsValidation from '../validations/news';
import validate from '../helpers/validate';

const router = express.Router();

router.get('/', validate(newsValidation.findNews), newsController.findNews);

export default router;
12 changes: 12 additions & 0 deletions src/validations/news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Joi } from 'celebrate';

export default {
findNews: {
query: Joi.object({
isActive: Joi.boolean().default(true),
afterDate: Joi.date(),
limit: Joi.number().integer().default(10),
offset: Joi.number().integer().default(0),
}),
},
};
Loading

0 comments on commit 3841143

Please sign in to comment.