mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-16 21:40:23 +01:00
Compare commits
1 Commits
v4.0.0-rc.
...
socket-not
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b08259e534 |
60
public/openapi/components/schemas/NotificationObject.yaml
Normal file
60
public/openapi/components/schemas/NotificationObject.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
NotificationObject:
|
||||||
|
allOf:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
importance:
|
||||||
|
type: number
|
||||||
|
datetime:
|
||||||
|
type: number
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
description: Relative path to the notification target
|
||||||
|
bodyShort:
|
||||||
|
type: string
|
||||||
|
nid:
|
||||||
|
type: string
|
||||||
|
datetimeISO:
|
||||||
|
type: string
|
||||||
|
read:
|
||||||
|
type: boolean
|
||||||
|
readClass:
|
||||||
|
type: string
|
||||||
|
- type: object
|
||||||
|
description: Optional properties that may or may not be present (except for `nid`, which is always present, and is only here as a hack to pass validation)
|
||||||
|
properties:
|
||||||
|
nid:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: Used to denote a classification of notification. These types are toggleable in the user ACP (so the user can opt to not receive notifications for certain types, etc.)
|
||||||
|
bodyLong:
|
||||||
|
type: string
|
||||||
|
from:
|
||||||
|
type: number
|
||||||
|
pid:
|
||||||
|
type: number
|
||||||
|
description: A post id, if the notification pertains to a post
|
||||||
|
tid:
|
||||||
|
type: number
|
||||||
|
description: A post id, if the notification pertains to a topic
|
||||||
|
user:
|
||||||
|
$ref: ./UserObject.yaml#/UserObjectTiny
|
||||||
|
subject:
|
||||||
|
type: string
|
||||||
|
description: A language key that would be used as an email subject, otherwise a generic "New Notification" message.
|
||||||
|
icon:
|
||||||
|
type: string
|
||||||
|
roomName:
|
||||||
|
type: string
|
||||||
|
description: The chat room name, if the notification is related to a chat message
|
||||||
|
roomIcon:
|
||||||
|
type: string
|
||||||
|
mergeId:
|
||||||
|
type: string
|
||||||
|
description: A common string used to denote related notifications that can be merged together (e.g. two new chat messages in same room)
|
||||||
|
image:
|
||||||
|
type: string
|
||||||
|
description: A URL to a media image for the notification (supercedes the user avatar if `user` is present)
|
||||||
|
nullable: true
|
||||||
|
required:
|
||||||
|
- nid
|
||||||
@@ -609,6 +609,33 @@ UserObjectSlim:
|
|||||||
type: string
|
type: string
|
||||||
description: An ISO 8601 formatted date string representing the moment a ban will be lifted, or the words "Not Banned"
|
description: An ISO 8601 formatted date string representing the moment a ban will be lifted, or the words "Not Banned"
|
||||||
example: Not Banned
|
example: Not Banned
|
||||||
|
UserObjectTiny:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: A friendly name for a given user account
|
||||||
|
userslug:
|
||||||
|
type: string
|
||||||
|
description: An URL-safe variant of the username (i.e. lower-cased, spaces
|
||||||
|
removed, etc.)
|
||||||
|
picture:
|
||||||
|
type: string
|
||||||
|
uid:
|
||||||
|
type: number
|
||||||
|
description: A user identifier
|
||||||
|
icon:text:
|
||||||
|
type: string
|
||||||
|
description: A single-letter representation of a username. This is used in the
|
||||||
|
auto-generated icon given to users without
|
||||||
|
an avatar
|
||||||
|
icon:bgColor:
|
||||||
|
type: string
|
||||||
|
description: A six-character hexadecimal colour code assigned to the user. This
|
||||||
|
value is used in conjunction with
|
||||||
|
`icon:text` for the user's auto-generated
|
||||||
|
icon
|
||||||
|
example: "#f44336"
|
||||||
UserObjectACP:
|
UserObjectACP:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
@@ -715,32 +742,7 @@ BanMuteArray:
|
|||||||
fromUid:
|
fromUid:
|
||||||
type: number
|
type: number
|
||||||
user:
|
user:
|
||||||
type: object
|
$ref: '#/UserObjectTiny'
|
||||||
properties:
|
|
||||||
username:
|
|
||||||
type: string
|
|
||||||
description: A friendly name for a given user account
|
|
||||||
userslug:
|
|
||||||
type: string
|
|
||||||
description: An URL-safe variant of the username (i.e. lower-cased, spaces
|
|
||||||
removed, etc.)
|
|
||||||
picture:
|
|
||||||
type: string
|
|
||||||
uid:
|
|
||||||
type: number
|
|
||||||
description: A user identifier
|
|
||||||
icon:text:
|
|
||||||
type: string
|
|
||||||
description: A single-letter representation of a username. This is used in the
|
|
||||||
auto-generated icon given to users without
|
|
||||||
an avatar
|
|
||||||
icon:bgColor:
|
|
||||||
type: string
|
|
||||||
description: A six-character hexadecimal colour code assigned to the user. This
|
|
||||||
value is used in conjunction with
|
|
||||||
`icon:text` for the user's auto-generated
|
|
||||||
icon
|
|
||||||
example: "#f44336"
|
|
||||||
until:
|
until:
|
||||||
type: number
|
type: number
|
||||||
untilReadable:
|
untilReadable:
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ paths:
|
|||||||
$ref: 'write/topics/tid/read.yaml'
|
$ref: 'write/topics/tid/read.yaml'
|
||||||
/topics/{tid}/bump:
|
/topics/{tid}/bump:
|
||||||
$ref: 'write/topics/tid/bump.yaml'
|
$ref: 'write/topics/tid/bump.yaml'
|
||||||
|
/notifications:
|
||||||
|
$ref: 'write/notifications.yaml'
|
||||||
|
/notifications/{nid}:
|
||||||
|
$ref: 'write/notifications/nid.yaml'
|
||||||
|
/notifications/count:
|
||||||
|
$ref: 'write/notifications/count.yaml'
|
||||||
/tags/{tag}/follow:
|
/tags/{tag}/follow:
|
||||||
$ref: 'write/tags/tag/follow.yaml'
|
$ref: 'write/tags/tag/follow.yaml'
|
||||||
/posts/{pid}:
|
/posts/{pid}:
|
||||||
|
|||||||
26
public/openapi/write/notifications.yaml
Normal file
26
public/openapi/write/notifications.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
summary: list notifications
|
||||||
|
description: This operation returns two lists of notifications — read and unread.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: notifications successfully listed
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
$ref: ../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
read:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: ../components/schemas/NotificationObject.yaml#/NotificationObject
|
||||||
|
unread:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: ../components/schemas/NotificationObject.yaml#/NotificationObject
|
||||||
20
public/openapi/write/notifications/count.yaml
Normal file
20
public/openapi/write/notifications/count.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
summary: get unread notification count
|
||||||
|
description: This operation returns the calling user's unread notifications count
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: unread notifications count successfully retrieved
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
$ref: ../../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
unread:
|
||||||
|
type: number
|
||||||
28
public/openapi/write/notifications/nid.yaml
Normal file
28
public/openapi/write/notifications/nid.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
summary: get notification
|
||||||
|
description: This operation returns the content of a single notification
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: nid
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
required: true
|
||||||
|
description: The notification id to retrieve
|
||||||
|
example: uploads:export:1
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: notification successfully retrieved
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
$ref: ../../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
notification:
|
||||||
|
$ref: ../../components/schemas/NotificationObject.yaml#/NotificationObject
|
||||||
@@ -8,7 +8,8 @@ define('notifications', [
|
|||||||
'tinycon',
|
'tinycon',
|
||||||
'hooks',
|
'hooks',
|
||||||
'alerts',
|
'alerts',
|
||||||
], function (translator, components, navigator, Tinycon, hooks, alerts) {
|
'api',
|
||||||
|
], function (translator, components, navigator, Tinycon, hooks, alerts, api) {
|
||||||
const Notifications = {};
|
const Notifications = {};
|
||||||
|
|
||||||
let unreadNotifs = {};
|
let unreadNotifs = {};
|
||||||
@@ -30,11 +31,7 @@ define('notifications', [
|
|||||||
|
|
||||||
Notifications.loadNotifications = function (notifList, callback) {
|
Notifications.loadNotifications = function (notifList, callback) {
|
||||||
callback = callback || function () {};
|
callback = callback || function () {};
|
||||||
socket.emit('notifications.get', null, function (err, data) {
|
api.get('/notifications').then((data) => {
|
||||||
if (err) {
|
|
||||||
return alerts.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
const notifs = data.unread.concat(data.read).sort(function (a, b) {
|
const notifs = data.unread.concat(data.read).sort(function (a, b) {
|
||||||
return parseInt(a.datetime, 10) > parseInt(b.datetime, 10) ? -1 : 1;
|
return parseInt(a.datetime, 10) > parseInt(b.datetime, 10) ? -1 : 1;
|
||||||
});
|
});
|
||||||
@@ -68,7 +65,7 @@ define('notifications', [
|
|||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}).catch(alerts.error);
|
||||||
};
|
};
|
||||||
|
|
||||||
Notifications.handleUnreadButton = function (notifList) {
|
Notifications.handleUnreadButton = function (notifList) {
|
||||||
@@ -94,13 +91,9 @@ define('notifications', [
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('notifications.getCount', function (err, count) {
|
api.get('/notifications/count').then(({ unread }) => {
|
||||||
if (err) {
|
Notifications.updateNotifCount(unread);
|
||||||
return alerts.error(err);
|
}).catch(alerts.error);
|
||||||
}
|
|
||||||
|
|
||||||
Notifications.updateNotifCount(count);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!unreadNotifs[notifData.nid]) {
|
if (!unreadNotifs[notifData.nid]) {
|
||||||
unreadNotifs[notifData.nid] = true;
|
unreadNotifs[notifData.nid] = true;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ module.exports = {
|
|||||||
users: require('./users'),
|
users: require('./users'),
|
||||||
groups: require('./groups'),
|
groups: require('./groups'),
|
||||||
topics: require('./topics'),
|
topics: require('./topics'),
|
||||||
|
notifications: require('./notifications'),
|
||||||
tags: require('./tags'),
|
tags: require('./tags'),
|
||||||
posts: require('./posts'),
|
posts: require('./posts'),
|
||||||
chats: require('./chats'),
|
chats: require('./chats'),
|
||||||
|
|||||||
22
src/api/notifications.js
Normal file
22
src/api/notifications.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const user = require('../user');
|
||||||
|
|
||||||
|
const notificationsApi = module.exports;
|
||||||
|
|
||||||
|
notificationsApi.list = async (caller) => {
|
||||||
|
const { read, unread } = await user.notifications.get(caller.uid);
|
||||||
|
return { read, unread };
|
||||||
|
};
|
||||||
|
|
||||||
|
notificationsApi.get = async (caller, { nid }) => {
|
||||||
|
let notification = await user.notifications.getNotifications([nid], caller.uid);
|
||||||
|
notification = notification.pop();
|
||||||
|
|
||||||
|
return { notification };
|
||||||
|
};
|
||||||
|
|
||||||
|
notificationsApi.getCount = async (caller) => {
|
||||||
|
const unread = await user.notifications.getUnreadCount(caller.uid);
|
||||||
|
return { unread };
|
||||||
|
};
|
||||||
@@ -6,6 +6,7 @@ Write.users = require('./users');
|
|||||||
Write.groups = require('./groups');
|
Write.groups = require('./groups');
|
||||||
Write.categories = require('./categories');
|
Write.categories = require('./categories');
|
||||||
Write.topics = require('./topics');
|
Write.topics = require('./topics');
|
||||||
|
Write.notifications = require('./notifications');
|
||||||
Write.tags = require('./tags');
|
Write.tags = require('./tags');
|
||||||
Write.posts = require('./posts');
|
Write.posts = require('./posts');
|
||||||
Write.chats = require('./chats');
|
Write.chats = require('./chats');
|
||||||
|
|||||||
22
src/controllers/write/notifications.js
Normal file
22
src/controllers/write/notifications.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const api = require('../../api');
|
||||||
|
|
||||||
|
const helpers = require('../helpers');
|
||||||
|
|
||||||
|
const Notifications = module.exports;
|
||||||
|
|
||||||
|
Notifications.get = async (req, res) => {
|
||||||
|
let response;
|
||||||
|
if (req.params.nid) {
|
||||||
|
response = await api.notifications.get(req, { ...req.params });
|
||||||
|
} else {
|
||||||
|
response = await api.notifications.list(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
helpers.formatApiResponse(200, res, response);
|
||||||
|
};
|
||||||
|
|
||||||
|
Notifications.getCount = async (req, res) => {
|
||||||
|
helpers.formatApiResponse(200, res, await api.notifications.getCount(req));
|
||||||
|
};
|
||||||
@@ -37,6 +37,7 @@ Write.reload = async (params) => {
|
|||||||
router.use('/api/v3/groups', require('./groups')());
|
router.use('/api/v3/groups', require('./groups')());
|
||||||
router.use('/api/v3/categories', require('./categories')());
|
router.use('/api/v3/categories', require('./categories')());
|
||||||
router.use('/api/v3/topics', require('./topics')());
|
router.use('/api/v3/topics', require('./topics')());
|
||||||
|
router.use('/api/v3/notifications', require('./notifications')());
|
||||||
router.use('/api/v3/tags', require('./tags')());
|
router.use('/api/v3/tags', require('./tags')());
|
||||||
router.use('/api/v3/posts', require('./posts')());
|
router.use('/api/v3/posts', require('./posts')());
|
||||||
router.use('/api/v3/chats', require('./chats')());
|
router.use('/api/v3/chats', require('./chats')());
|
||||||
|
|||||||
18
src/routes/write/notifications.js
Normal file
18
src/routes/write/notifications.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const router = require('express').Router();
|
||||||
|
const middleware = require('../../middleware');
|
||||||
|
const controllers = require('../../controllers');
|
||||||
|
const routeHelpers = require('../helpers');
|
||||||
|
|
||||||
|
const { setupApiRoute } = routeHelpers;
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
const middlewares = [middleware.ensureLoggedIn];
|
||||||
|
|
||||||
|
setupApiRoute(router, 'get', '/count', [...middlewares], controllers.write.notifications.getCount);
|
||||||
|
|
||||||
|
setupApiRoute(router, 'get', '/:nid?', [...middlewares], controllers.write.notifications.get);
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -2,18 +2,35 @@
|
|||||||
|
|
||||||
const user = require('../user');
|
const user = require('../user');
|
||||||
const notifications = require('../notifications');
|
const notifications = require('../notifications');
|
||||||
|
const api = require('../api');
|
||||||
|
|
||||||
|
const sockets = require('.');
|
||||||
|
|
||||||
const SocketNotifs = module.exports;
|
const SocketNotifs = module.exports;
|
||||||
|
|
||||||
SocketNotifs.get = async function (socket, data) {
|
SocketNotifs.get = async function (socket, data) {
|
||||||
|
sockets.warnDeprecated(socket, 'GET /api/v3/notifications/(:nid)');
|
||||||
|
|
||||||
|
// Passing in multiple nids is no longer supported in apiv3
|
||||||
if (data && Array.isArray(data.nids) && socket.uid) {
|
if (data && Array.isArray(data.nids) && socket.uid) {
|
||||||
return await user.notifications.getNotifications(data.nids, socket.uid);
|
const notifications = await Promise.all(data.nids.map(async (nid) => {
|
||||||
|
const { notification } = await api.notifications.get(socket, { nid });
|
||||||
|
return notification;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return notifications;
|
||||||
}
|
}
|
||||||
return await user.notifications.get(socket.uid);
|
|
||||||
|
const response = await api.notifications.list(socket);
|
||||||
|
response.uid = socket.uid;
|
||||||
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketNotifs.getCount = async function (socket) {
|
SocketNotifs.getCount = async function (socket) {
|
||||||
return await user.notifications.getUnreadCount(socket.uid);
|
sockets.warnDeprecated(socket, 'GET /api/v3/notifications/count');
|
||||||
|
|
||||||
|
const { unread } = await api.notifications.getCount(socket);
|
||||||
|
return unread;
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketNotifs.deleteAll = async function (socket) {
|
SocketNotifs.deleteAll = async function (socket) {
|
||||||
|
|||||||
Reference in New Issue
Block a user