Skip to content

Commit

Permalink
app notification v2 (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joao Pedro da Silva authored May 20, 2022
1 parent 00c17d0 commit b9d9101
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 21 deletions.
54 changes: 54 additions & 0 deletions packages/api/src/controllers/v2/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,60 @@ class UserController {
.then((r) => standardResponse(res, 201, true, r))
.catch((e) => standardResponse(res, 400, false, '', { error: e }));
};

public getNotifications = (req: RequestWithUser, res: Response) => {
if (req.user === undefined) {
standardResponse(res, 401, false, '', {
error: {
name: 'USER_NOT_FOUND',
message: 'User not identified!',
},
});
return;
}

this.userService.getNotifications(req.query, req.user.userId)
.then((r) => standardResponse(res, 200, true, r))
.catch((e) =>
standardResponse(res, 400, false, '', { error: e.message })
);
};

public readNotifications = (req: RequestWithUser, res: Response) => {
if (req.user === undefined) {
standardResponse(res, 401, false, '', {
error: {
name: 'USER_NOT_FOUND',
message: 'User not identified!',
},
});
return;
}

this.userService.readNotifications(req.user.userId)
.then((r) => standardResponse(res, 200, true, r))
.catch((e) =>
standardResponse(res, 400, false, '', { error: e.message })
);
};

public getUnreadNotifications = (req: RequestWithUser, res: Response) => {
if (req.user === undefined) {
standardResponse(res, 401, false, '', {
error: {
name: 'USER_NOT_FOUND',
message: 'User not identified!',
},
});
return;
}

this.userService.getUnreadNotifications(req.user.userId)
.then((r) => standardResponse(res, 200, true, r))
.catch((e) =>
standardResponse(res, 400, false, '', { error: e.message })
);
};
}

export default UserController;
105 changes: 105 additions & 0 deletions packages/api/src/routes/v2/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,109 @@ export default (app: Router): void => {
authenticateToken,
userController.getPresignedUrlMedia
);

/**
* @swagger
*
* /users/notifications/unread:
* get:
* tags:
* - "users"
* summary: Get the number of unread notifications from a user
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* type: integer
* description: number of unread notifications
* security:
* - api_auth:
* - "write:modify":
*/
route.get(
'/notifications/unread',
authenticateToken,
userController.getUnreadNotifications
);

/**
* @swagger
*
* /users/notifications:
* get:
* tags:
* - "users"
* summary: Get all notifications from a user
* parameters:
* - in: query
* name: offset
* schema:
* type: integer
* required: false
* description: offset used for community pagination (default 0)
* - in: query
* name: limit
* schema:
* type: integer
* required: false
* description: limit used for community pagination (default 10)
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* $ref: '#/components/schemas/AppNotification'
* security:
* - api_auth:
* - "write:modify":
*/
route.get(
'/notifications/:query?',
authenticateToken,
userController.getNotifications
);

/**
* @swagger
*
* /users/notifications/read:
* put:
* tags:
* - "users"
* summary: Mark all notifications as read
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* type: boolean
* description: if true the notification was updated
* security:
* - api_auth:
* - "write:modify":
*/
route.put(
'/notifications/read',
authenticateToken,
userController.readNotifications
);
};
6 changes: 3 additions & 3 deletions packages/core/src/services/app/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,9 @@ export default class UserService {
address: {
[Op.not]: address,
},
active: true
}
})
active: true,
},
});

return !!user;
}
Expand Down
96 changes: 78 additions & 18 deletions packages/core/src/services/app/user/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Op, QueryTypes } from 'sequelize';
import { Op } from 'sequelize';

import config from '../../../config';
import { models, sequelize } from '../../../database';
import { AppUserModel } from '../../../database/models/app/appUser';
import { LogTypes } from '../../../interfaces/app/appLog';
import { AppNotification } from '../../../interfaces/app/appNotification';
import {
AppUser,
AppUserCreationAttributes,
AppUserUpdate,
} from '../../../interfaces/app/appUser';
Expand All @@ -23,7 +24,7 @@ export default class UserService {
userParams: AppUserCreationAttributes,
overwrite: boolean = false,
recover: boolean = false,
clientId?: string,
clientId?: string
) {
const exists = await this._exists(userParams.address);

Expand Down Expand Up @@ -74,17 +75,20 @@ export default class UserService {
// provided phone number are the same
const jsonUser = user.toJSON();
if (!jsonUser.phone && userParams.phone) {
await models.appUser.update({
phone: userParams.phone
}, {
where: {
id: jsonUser.id,
await models.appUser.update(
{
phone: userParams.phone,
},
{
where: {
id: jsonUser.id,
},
}
});
);
user.phone = userParams.phone;
} else if (
jsonUser.phone &&
userParams.phone &&
jsonUser.phone &&
userParams.phone &&
userParams.phone !== jsonUser.phone
) {
throw new BaseError(
Expand Down Expand Up @@ -112,11 +116,15 @@ export default class UserService {
const credential = await models.appClientCredential.findOne({
where: {
clientId,
status: 'active'
}
status: 'active',
},
});
if (credential) {
token = generateAccessToken(userParams.address, user.id, clientId);
token = generateAccessToken(
userParams.address,
user.id,
clientId
);
} else {
throw new BaseError(
'INVALID_CREDENTIAL',
Expand Down Expand Up @@ -153,7 +161,10 @@ export default class UserService {

public async update(user: AppUserUpdate) {
if (user.phone) {
const existsPhone = await this._existsAccountByPhone(user.phone, user.address);
const existsPhone = await this._existsAccountByPhone(
user.phone,
user.address
);

if (existsPhone)
throw new BaseError(
Expand Down Expand Up @@ -264,6 +275,55 @@ export default class UserService {
}
}

public async getNotifications(
query: {
offset?: string;
limit?: string;
},
userId: number
): Promise<AppNotification[]> {
const notifications = await models.appNotification.findAll({
where: {
userId,
},
offset: query.offset
? parseInt(query.offset, 10)
: config.defaultOffset,
limit: query.limit
? parseInt(query.limit, 10)
: config.defaultLimit,
order: [['createdAt', 'DESC']],
});
return notifications as AppNotification[];
}

public async readNotifications(userId: number): Promise<boolean> {
const updated = await models.appNotification.update(
{
read: true,
},
{
returning: true,
where: {
userId,
},
}
);
if (updated[0] === 0) {
throw new Error('notifications were not updated!');
}
return true;
}

public async getUnreadNotifications(userId: number): Promise<number> {
return models.appNotification.count({
where: {
userId,
read: false,
},
});
}

private async _overwriteUser(user: AppUserCreationAttributes) {
try {
const usersToInactive = await models.appUser.findAll({
Expand Down Expand Up @@ -333,9 +393,9 @@ export default class UserService {
address: {
[Op.not]: address,
},
active: true
}
})
active: true,
},
});

return !!user;
}
Expand Down

0 comments on commit b9d9101

Please sign in to comment.