@nocobase/plugin-notification-in-app-message 1.4.0-alpha.20241027230531
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +159 -0
- package/README.md +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/MessageManagerProvider.d.ts +10 -0
- package/dist/client/components/ContentConfigForm.d.ts +12 -0
- package/dist/client/components/Inbox.d.ts +18 -0
- package/dist/client/components/InboxContent.d.ts +10 -0
- package/dist/client/components/MessageConfigForm.d.ts +12 -0
- package/dist/client/components/MessageList.d.ts +10 -0
- package/dist/client/components/UsersAddition.d.ts +10 -0
- package/dist/client/components/UsersSelect.d.ts +18 -0
- package/dist/client/components/hooks/useChat.d.ts +36 -0
- package/dist/client/index.d.ts +15 -0
- package/dist/client/index.js +24 -0
- package/dist/client/observables/channel.d.ts +37 -0
- package/dist/client/observables/inbox.d.ts +11 -0
- package/dist/client/observables/index.d.ts +13 -0
- package/dist/client/observables/message.d.ts +33 -0
- package/dist/client/observables/sse.d.ts +5 -0
- package/dist/client/observables/user.d.ts +11 -0
- package/dist/client/utils.d.ts +11 -0
- package/dist/externalVersion.js +29 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +48 -0
- package/dist/locale/en-US.json +22 -0
- package/dist/locale/index.d.ts +12 -0
- package/dist/locale/index.js +55 -0
- package/dist/locale/zh-CN.json +21 -0
- package/dist/server/InAppNotificationChannel.d.ts +41 -0
- package/dist/server/InAppNotificationChannel.js +162 -0
- package/dist/server/collections/messages.d.ts +10 -0
- package/dist/server/collections/messages.js +33 -0
- package/dist/server/defineMyInAppChannels.d.ts +12 -0
- package/dist/server/defineMyInAppChannels.js +159 -0
- package/dist/server/defineMyInAppMessages.d.ts +15 -0
- package/dist/server/defineMyInAppMessages.js +123 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.js +42 -0
- package/dist/server/parseUserSelectionConf.d.ts +10 -0
- package/dist/server/parseUserSelectionConf.js +51 -0
- package/dist/server/plugin.d.ts +19 -0
- package/dist/server/plugin.js +72 -0
- package/dist/types/channels.d.ts +18 -0
- package/dist/types/channels.js +93 -0
- package/dist/types/index.d.ts +64 -0
- package/dist/types/index.js +62 -0
- package/dist/types/messages.d.ts +10 -0
- package/dist/types/messages.js +129 -0
- package/dist/types/sse.d.ts +20 -0
- package/dist/types/sse.js +24 -0
- package/package.json +25 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Inbox": "Inbox",
|
|
3
|
+
"Message": "Message",
|
|
4
|
+
"Loading more": "Loading more",
|
|
5
|
+
"Detail": "Detail",
|
|
6
|
+
"Content": "Content",
|
|
7
|
+
"Datetime": "Datetime",
|
|
8
|
+
"Status": "Status",
|
|
9
|
+
"All": "All",
|
|
10
|
+
"Read": "Read",
|
|
11
|
+
"Unread": "Unread",
|
|
12
|
+
"In-app message": "In-app message",
|
|
13
|
+
"Receivers": "Receivers",
|
|
14
|
+
"Channel name": "Channel name",
|
|
15
|
+
"Message group name": "Message group name",
|
|
16
|
+
"Message title": "Message title",
|
|
17
|
+
"Message content": "Message content",
|
|
18
|
+
"Inapp Message": "Inapp Message",
|
|
19
|
+
"Detail URL": "Detail URL",
|
|
20
|
+
"Support two types of links in nocobase: internal links and external links. If using an internal link, the link starts with '/', for example, '/admin/page'. If using an external link, the link starts with 'http', for example, 'https://example.com'.": "Support two types of links in nocobase: internal links and external links. If using an internal link, the link starts with '/', for example, '/admin/page'. If using an external link, the link starts with 'http', for example, 'https://example.com'.",
|
|
21
|
+
"Mark as read": "Mark as read"
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
export declare const NAMESPACE = "notification-in-app-message";
|
|
10
|
+
export declare function lang(key: string): string;
|
|
11
|
+
export declare function generateNTemplate(key: string): string;
|
|
12
|
+
export declare function useLocalTranslation(): import("react-i18next").UseTranslationResponse<("notification-in-app-message" | "client")[], undefined>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var locale_exports = {};
|
|
28
|
+
__export(locale_exports, {
|
|
29
|
+
NAMESPACE: () => NAMESPACE,
|
|
30
|
+
generateNTemplate: () => generateNTemplate,
|
|
31
|
+
lang: () => lang,
|
|
32
|
+
useLocalTranslation: () => useLocalTranslation
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(locale_exports);
|
|
35
|
+
var import_client = require("@nocobase/client");
|
|
36
|
+
var import_react_i18next = require("react-i18next");
|
|
37
|
+
const NAMESPACE = "notification-in-app-message";
|
|
38
|
+
function lang(key) {
|
|
39
|
+
return import_client.i18n.t(key, { ns: NAMESPACE });
|
|
40
|
+
}
|
|
41
|
+
function generateNTemplate(key) {
|
|
42
|
+
return `{{t('${key}', { ns: '${NAMESPACE}', nsMode: 'fallback' })}}`;
|
|
43
|
+
}
|
|
44
|
+
function useLocalTranslation() {
|
|
45
|
+
return (0, import_react_i18next.useTranslation)([NAMESPACE, "client"], {
|
|
46
|
+
nsMode: "fallback"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
NAMESPACE,
|
|
52
|
+
generateNTemplate,
|
|
53
|
+
lang,
|
|
54
|
+
useLocalTranslation
|
|
55
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Inbox": "收信箱",
|
|
3
|
+
"Message": "消息",
|
|
4
|
+
"Loading more": "加载更多",
|
|
5
|
+
"Detail": "详情",
|
|
6
|
+
"Content": "内容",
|
|
7
|
+
"Datetime": "时间",
|
|
8
|
+
"Status": "状态",
|
|
9
|
+
"Read": "已读",
|
|
10
|
+
"Unread": "未读",
|
|
11
|
+
"All": "全部",
|
|
12
|
+
"In-app message": "站内信",
|
|
13
|
+
"Receivers": "接收人",
|
|
14
|
+
"Message group name": "消息分组名称",
|
|
15
|
+
"Message title": "消息标题",
|
|
16
|
+
"Message content": "消息内容",
|
|
17
|
+
"Inapp Message": "站内信",
|
|
18
|
+
"Detail URL": "详情链接",
|
|
19
|
+
"Support two types of links in nocobase: internal links and external links. If using an internal link, the link starts with '/', for example, '/admin/page'. If using an external link, the link starts with 'http', for example, 'https://example.com'.": "nocobase支持两种链接类型:内部链接和外部链接。如果使用内部链接,链接以'/'开头,例如,'/admin/page'。如果使用外部链接,链接以'http'开头,例如,'https://example.com'。",
|
|
20
|
+
"Mark as read": "标记为已读"
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="node" />
|
|
10
|
+
import { Application } from '@nocobase/server';
|
|
11
|
+
import { SendFnType, BaseNotificationChannel } from '@nocobase/plugin-notification-manager';
|
|
12
|
+
import { InAppMessageFormValues } from '../types';
|
|
13
|
+
import { PassThrough } from 'stream';
|
|
14
|
+
type UserID = string;
|
|
15
|
+
type ClientID = string;
|
|
16
|
+
export default class InAppNotificationChannel extends BaseNotificationChannel {
|
|
17
|
+
protected app: Application;
|
|
18
|
+
userClientsMap: Record<UserID, Record<ClientID, PassThrough>>;
|
|
19
|
+
constructor(app: Application);
|
|
20
|
+
load(): Promise<void>;
|
|
21
|
+
onMessageCreatedOrUpdated: () => Promise<void>;
|
|
22
|
+
addClient: (userId: UserID, clientId: ClientID, stream: PassThrough) => void;
|
|
23
|
+
getClient: (userId: UserID, clientId: ClientID) => PassThrough;
|
|
24
|
+
removeClient: (userId: UserID, clientId: ClientID) => void;
|
|
25
|
+
sendDataToUser(userId: UserID, message: {
|
|
26
|
+
type: string;
|
|
27
|
+
data: any;
|
|
28
|
+
}): void;
|
|
29
|
+
saveMessageToDB: ({ content, status, userId, title, channelName, receiveTimestamp, options, }: {
|
|
30
|
+
content: string;
|
|
31
|
+
userId: number;
|
|
32
|
+
title: string;
|
|
33
|
+
channelName: string;
|
|
34
|
+
status: 'read' | 'unread';
|
|
35
|
+
receiveTimestamp?: number;
|
|
36
|
+
options?: Record<string, any>;
|
|
37
|
+
}) => Promise<any>;
|
|
38
|
+
send: SendFnType<InAppMessageFormValues>;
|
|
39
|
+
defineActions(): void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var InAppNotificationChannel_exports = {};
|
|
38
|
+
__export(InAppNotificationChannel_exports, {
|
|
39
|
+
default: () => InAppNotificationChannel
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(InAppNotificationChannel_exports);
|
|
42
|
+
var import_plugin_notification_manager = require("@nocobase/plugin-notification-manager");
|
|
43
|
+
var import_types2 = require("../types");
|
|
44
|
+
var import_parseUserSelectionConf = require("./parseUserSelectionConf");
|
|
45
|
+
var import_defineMyInAppMessages = __toESM(require("./defineMyInAppMessages"));
|
|
46
|
+
var import_defineMyInAppChannels = __toESM(require("./defineMyInAppChannels"));
|
|
47
|
+
class InAppNotificationChannel extends import_plugin_notification_manager.BaseNotificationChannel {
|
|
48
|
+
constructor(app) {
|
|
49
|
+
super(app);
|
|
50
|
+
this.app = app;
|
|
51
|
+
this.userClientsMap = {};
|
|
52
|
+
}
|
|
53
|
+
userClientsMap;
|
|
54
|
+
async load() {
|
|
55
|
+
this.onMessageCreatedOrUpdated();
|
|
56
|
+
this.defineActions();
|
|
57
|
+
}
|
|
58
|
+
onMessageCreatedOrUpdated = async () => {
|
|
59
|
+
this.app.db.on(`${import_types2.InAppMessagesDefinition.name}.afterUpdate`, async (model, options) => {
|
|
60
|
+
const userId = model.userId;
|
|
61
|
+
this.sendDataToUser(userId, { type: "message:updated", data: model.dataValues });
|
|
62
|
+
});
|
|
63
|
+
this.app.db.on(`${import_types2.InAppMessagesDefinition.name}.afterCreate`, async (model, options) => {
|
|
64
|
+
const userId = model.userId;
|
|
65
|
+
this.sendDataToUser(userId, { type: "message:created", data: model.dataValues });
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
addClient = (userId, clientId, stream) => {
|
|
69
|
+
if (!this.userClientsMap[userId]) {
|
|
70
|
+
this.userClientsMap[userId] = {};
|
|
71
|
+
}
|
|
72
|
+
this.userClientsMap[userId][clientId] = stream;
|
|
73
|
+
};
|
|
74
|
+
getClient = (userId, clientId) => {
|
|
75
|
+
var _a;
|
|
76
|
+
return (_a = this.userClientsMap[userId]) == null ? void 0 : _a[clientId];
|
|
77
|
+
};
|
|
78
|
+
removeClient = (userId, clientId) => {
|
|
79
|
+
if (this.userClientsMap[userId]) {
|
|
80
|
+
delete this.userClientsMap[userId][clientId];
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
sendDataToUser(userId, message) {
|
|
84
|
+
const clients = this.userClientsMap[userId];
|
|
85
|
+
if (clients) {
|
|
86
|
+
for (const clientId in clients) {
|
|
87
|
+
const stream = clients[clientId];
|
|
88
|
+
stream.write(
|
|
89
|
+
`data: ${JSON.stringify({
|
|
90
|
+
type: message.type,
|
|
91
|
+
data: {
|
|
92
|
+
...message.data,
|
|
93
|
+
title: message.data.title.slice(0, 30),
|
|
94
|
+
content: message.data.content.slice(0, 105)
|
|
95
|
+
}
|
|
96
|
+
})}
|
|
97
|
+
|
|
98
|
+
`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
saveMessageToDB = async ({
|
|
104
|
+
content,
|
|
105
|
+
status,
|
|
106
|
+
userId,
|
|
107
|
+
title,
|
|
108
|
+
channelName,
|
|
109
|
+
receiveTimestamp,
|
|
110
|
+
options = {}
|
|
111
|
+
}) => {
|
|
112
|
+
const messagesRepo = this.app.db.getRepository(import_types2.InAppMessagesDefinition.name);
|
|
113
|
+
const message = await messagesRepo.create({
|
|
114
|
+
values: {
|
|
115
|
+
content,
|
|
116
|
+
title,
|
|
117
|
+
channelName,
|
|
118
|
+
status,
|
|
119
|
+
userId,
|
|
120
|
+
receiveTimestamp: receiveTimestamp ?? Date.now(),
|
|
121
|
+
options
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return message;
|
|
125
|
+
};
|
|
126
|
+
send = async (params) => {
|
|
127
|
+
const { channel, message, receivers } = params;
|
|
128
|
+
let userIds;
|
|
129
|
+
const { content, title, options = {} } = message;
|
|
130
|
+
const userRepo = this.app.db.getRepository("users");
|
|
131
|
+
if ((receivers == null ? void 0 : receivers.type) === "userId") {
|
|
132
|
+
userIds = receivers.value;
|
|
133
|
+
} else {
|
|
134
|
+
userIds = (await (0, import_parseUserSelectionConf.parseUserSelectionConf)(message.receivers, userRepo)).map((i) => parseInt(i));
|
|
135
|
+
}
|
|
136
|
+
await Promise.all(
|
|
137
|
+
userIds.map(async (userId) => {
|
|
138
|
+
await this.saveMessageToDB({
|
|
139
|
+
title,
|
|
140
|
+
content,
|
|
141
|
+
status: "unread",
|
|
142
|
+
userId,
|
|
143
|
+
channelName: channel.name,
|
|
144
|
+
options
|
|
145
|
+
});
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
return { status: "success", message };
|
|
149
|
+
};
|
|
150
|
+
defineActions() {
|
|
151
|
+
(0, import_defineMyInAppMessages.default)({
|
|
152
|
+
app: this.app,
|
|
153
|
+
addClient: this.addClient,
|
|
154
|
+
removeClient: this.removeClient,
|
|
155
|
+
getClient: this.getClient
|
|
156
|
+
});
|
|
157
|
+
(0, import_defineMyInAppChannels.default)({ app: this.app });
|
|
158
|
+
this.app.acl.allow("myInAppMessages", "*", "loggedIn");
|
|
159
|
+
this.app.acl.allow("myInAppChannels", "*", "loggedIn");
|
|
160
|
+
this.app.acl.allow("notificationInAppMessages", "*", "loggedIn");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { messageCollection } from '../../types/messages';
|
|
10
|
+
export default messageCollection;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var messages_exports = {};
|
|
28
|
+
__export(messages_exports, {
|
|
29
|
+
default: () => messages_default
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(messages_exports);
|
|
32
|
+
var import_messages = require("../../types/messages");
|
|
33
|
+
var messages_default = import_messages.messageCollection;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Application } from '@nocobase/server';
|
|
10
|
+
export default function defineMyInAppChannels({ app }: {
|
|
11
|
+
app: Application;
|
|
12
|
+
}): void;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var defineMyInAppChannels_exports = {};
|
|
28
|
+
__export(defineMyInAppChannels_exports, {
|
|
29
|
+
default: () => defineMyInAppChannels
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(defineMyInAppChannels_exports);
|
|
32
|
+
var import_sequelize = require("sequelize");
|
|
33
|
+
var import_plugin_notification_manager = require("@nocobase/plugin-notification-manager");
|
|
34
|
+
var import_types = require("../types");
|
|
35
|
+
function defineMyInAppChannels({ app }) {
|
|
36
|
+
app.resourceManager.define({
|
|
37
|
+
name: "myInAppChannels",
|
|
38
|
+
actions: {
|
|
39
|
+
list: {
|
|
40
|
+
handler: async (ctx) => {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
const { filter = {}, limit = 30 } = ((_a = ctx.action) == null ? void 0 : _a.params) ?? {};
|
|
43
|
+
const messagesCollection = app.db.getCollection(import_types.InAppMessagesDefinition.name);
|
|
44
|
+
const messagesTableName = messagesCollection.getRealTableName(true);
|
|
45
|
+
const channelsCollection = app.db.getCollection(import_plugin_notification_manager.ChannelsCollectionDefinition.name);
|
|
46
|
+
const channelsTableAliasName = app.db.sequelize.getQueryInterface().quoteIdentifier(channelsCollection.name);
|
|
47
|
+
const channelsFieldName = {
|
|
48
|
+
name: channelsCollection.getRealFieldName(import_plugin_notification_manager.ChannelsCollectionDefinition.fieldNameMap.name, true)
|
|
49
|
+
};
|
|
50
|
+
const messagesFieldName = {
|
|
51
|
+
channelName: messagesCollection.getRealFieldName(import_types.InAppMessagesDefinition.fieldNameMap.channelName, true),
|
|
52
|
+
status: messagesCollection.getRealFieldName(import_types.InAppMessagesDefinition.fieldNameMap.status, true),
|
|
53
|
+
userId: messagesCollection.getRealFieldName(import_types.InAppMessagesDefinition.fieldNameMap.userId, true),
|
|
54
|
+
receiveTimestamp: messagesCollection.getRealFieldName(
|
|
55
|
+
import_types.InAppMessagesDefinition.fieldNameMap.receiveTimestamp,
|
|
56
|
+
true
|
|
57
|
+
),
|
|
58
|
+
title: messagesCollection.getRealFieldName(import_types.InAppMessagesDefinition.fieldNameMap.title, true)
|
|
59
|
+
};
|
|
60
|
+
const userId = ctx.state.currentUser.id;
|
|
61
|
+
const userFilter = userId ? {
|
|
62
|
+
name: {
|
|
63
|
+
[import_sequelize.Op.in]: import_sequelize.Sequelize.literal(`(
|
|
64
|
+
SELECT messages.${messagesFieldName.channelName}
|
|
65
|
+
FROM ${messagesTableName} AS messages
|
|
66
|
+
WHERE
|
|
67
|
+
messages.${messagesFieldName.userId} = ${userId}
|
|
68
|
+
)`)
|
|
69
|
+
}
|
|
70
|
+
} : null;
|
|
71
|
+
const latestMsgReceiveTimestampSQL = `(
|
|
72
|
+
SELECT messages.${messagesFieldName.receiveTimestamp}
|
|
73
|
+
FROM ${messagesTableName} AS messages
|
|
74
|
+
WHERE
|
|
75
|
+
messages.${messagesFieldName.channelName} = ${channelsTableAliasName}.${channelsFieldName.name}
|
|
76
|
+
ORDER BY messages.${messagesFieldName.receiveTimestamp} DESC
|
|
77
|
+
LIMIT 1
|
|
78
|
+
)`;
|
|
79
|
+
const latestMsgReceiveTSFilter = ((_b = filter == null ? void 0 : filter.latestMsgReceiveTimestamp) == null ? void 0 : _b.$lt) ? import_sequelize.Sequelize.literal(`${latestMsgReceiveTimestampSQL} < ${filter.latestMsgReceiveTimestamp.$lt}`) : null;
|
|
80
|
+
const channelIdFilter = (filter == null ? void 0 : filter.id) ? { id: filter.id } : null;
|
|
81
|
+
const statusMap = {
|
|
82
|
+
all: "read|unread",
|
|
83
|
+
unread: "unread",
|
|
84
|
+
read: "read"
|
|
85
|
+
};
|
|
86
|
+
const filterChannelsByStatusSQL = ({ status }) => {
|
|
87
|
+
const sql = import_sequelize.Sequelize.literal(`(
|
|
88
|
+
SELECT messages.${messagesFieldName.channelName}
|
|
89
|
+
FROM ${messagesTableName} AS messages
|
|
90
|
+
WHERE messages.${messagesFieldName.status} = '${status}'
|
|
91
|
+
)`);
|
|
92
|
+
return { name: { [import_sequelize.Op.in]: sql } };
|
|
93
|
+
};
|
|
94
|
+
const channelStatusFilter = filter.status === "all" || !filter.status ? null : filterChannelsByStatusSQL({ status: statusMap[filter.status] });
|
|
95
|
+
const channelsRepo = app.db.getRepository(import_plugin_notification_manager.ChannelsCollectionDefinition.name);
|
|
96
|
+
try {
|
|
97
|
+
const channelsRes = channelsRepo.find({
|
|
98
|
+
logging: console.log,
|
|
99
|
+
limit,
|
|
100
|
+
attributes: {
|
|
101
|
+
include: [
|
|
102
|
+
[
|
|
103
|
+
import_sequelize.Sequelize.literal(`(
|
|
104
|
+
SELECT COUNT(*)
|
|
105
|
+
FROM ${messagesTableName} AS messages
|
|
106
|
+
WHERE
|
|
107
|
+
messages.${messagesFieldName.channelName} = ${channelsTableAliasName}.${channelsFieldName.name}
|
|
108
|
+
AND messages.${messagesFieldName.userId} = ${userId}
|
|
109
|
+
)`),
|
|
110
|
+
"totalMsgCnt"
|
|
111
|
+
],
|
|
112
|
+
[import_sequelize.Sequelize.literal(`'${userId}'`), "userId"],
|
|
113
|
+
[
|
|
114
|
+
import_sequelize.Sequelize.literal(`(
|
|
115
|
+
SELECT COUNT(*)
|
|
116
|
+
FROM ${messagesTableName} AS messages
|
|
117
|
+
WHERE
|
|
118
|
+
messages.${messagesFieldName.channelName} = ${channelsTableAliasName}.${channelsFieldName.name}
|
|
119
|
+
AND messages.${messagesFieldName.status} = 'unread'
|
|
120
|
+
AND messages.${messagesFieldName.userId} = ${userId}
|
|
121
|
+
)`),
|
|
122
|
+
"unreadMsgCnt"
|
|
123
|
+
],
|
|
124
|
+
[import_sequelize.Sequelize.literal(latestMsgReceiveTimestampSQL), "latestMsgReceiveTimestamp"],
|
|
125
|
+
[
|
|
126
|
+
import_sequelize.Sequelize.literal(`(
|
|
127
|
+
SELECT messages.${messagesFieldName.title}
|
|
128
|
+
FROM ${messagesTableName} AS messages
|
|
129
|
+
WHERE
|
|
130
|
+
messages.${messagesFieldName.channelName} = ${channelsTableAliasName}.${channelsFieldName.name}
|
|
131
|
+
ORDER BY messages.${messagesFieldName.receiveTimestamp} DESC
|
|
132
|
+
LIMIT 1
|
|
133
|
+
)`),
|
|
134
|
+
"latestMsgTitle"
|
|
135
|
+
]
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
order: [[import_sequelize.Sequelize.literal("latestMsgReceiveTimestamp"), "DESC"]],
|
|
139
|
+
//@ts-ignore
|
|
140
|
+
where: {
|
|
141
|
+
[import_sequelize.Op.and]: [userFilter, latestMsgReceiveTSFilter, channelIdFilter, channelStatusFilter].filter(Boolean)
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const countRes = channelsRepo.count({
|
|
145
|
+
//@ts-ignore
|
|
146
|
+
where: {
|
|
147
|
+
[import_sequelize.Op.and]: [userFilter, channelStatusFilter].filter(Boolean)
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const [channels, count] = await Promise.all([channelsRes, countRes]);
|
|
151
|
+
ctx.body = { rows: channels, count };
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error(error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Application } from '@nocobase/server';
|
|
10
|
+
export default function defineMyInAppMessages({ app, addClient, removeClient, getClient, }: {
|
|
11
|
+
app: Application;
|
|
12
|
+
addClient: any;
|
|
13
|
+
removeClient: any;
|
|
14
|
+
getClient: any;
|
|
15
|
+
}): void;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var defineMyInAppMessages_exports = {};
|
|
28
|
+
__export(defineMyInAppMessages_exports, {
|
|
29
|
+
default: () => defineMyInAppMessages
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(defineMyInAppMessages_exports);
|
|
32
|
+
var import_sequelize = require("sequelize");
|
|
33
|
+
var import_stream = require("stream");
|
|
34
|
+
var import_types = require("../types");
|
|
35
|
+
var import_plugin_notification_manager = require("@nocobase/plugin-notification-manager");
|
|
36
|
+
function defineMyInAppMessages({
|
|
37
|
+
app,
|
|
38
|
+
addClient,
|
|
39
|
+
removeClient,
|
|
40
|
+
getClient
|
|
41
|
+
}) {
|
|
42
|
+
const countTotalUnreadMessages = async (userId) => {
|
|
43
|
+
const messagesRepo = app.db.getRepository(import_types.InAppMessagesDefinition.name);
|
|
44
|
+
const channelsCollection = app.db.getCollection(import_plugin_notification_manager.ChannelsCollectionDefinition.name);
|
|
45
|
+
const channelsTableName = channelsCollection.getRealTableName(true);
|
|
46
|
+
const channelsFieldName = {
|
|
47
|
+
name: channelsCollection.getRealFieldName(import_plugin_notification_manager.ChannelsCollectionDefinition.fieldNameMap.name, true)
|
|
48
|
+
};
|
|
49
|
+
const count = await messagesRepo.count({
|
|
50
|
+
logging: console.log,
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
where: {
|
|
53
|
+
userId,
|
|
54
|
+
status: "unread",
|
|
55
|
+
channelName: {
|
|
56
|
+
[import_sequelize.Op.in]: import_sequelize.Sequelize.literal(`(select ${channelsFieldName.name} from ${channelsTableName})`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return count;
|
|
61
|
+
};
|
|
62
|
+
app.resourceManager.define({
|
|
63
|
+
name: "myInAppMessages",
|
|
64
|
+
actions: {
|
|
65
|
+
sse: {
|
|
66
|
+
handler: async (ctx, next) => {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
const userId = ctx.state.currentUser.id;
|
|
69
|
+
const clientId = (_b = (_a = ctx.action) == null ? void 0 : _a.params) == null ? void 0 : _b.id;
|
|
70
|
+
if (!clientId) return;
|
|
71
|
+
ctx.request.socket.setTimeout(0);
|
|
72
|
+
ctx.req.socket.setNoDelay(true);
|
|
73
|
+
ctx.req.socket.setKeepAlive(true);
|
|
74
|
+
ctx.set({
|
|
75
|
+
"Content-Type": "text/event-stream",
|
|
76
|
+
"Cache-Control": "no-cache",
|
|
77
|
+
Connection: "keep-alive"
|
|
78
|
+
});
|
|
79
|
+
const stream = new import_stream.PassThrough();
|
|
80
|
+
ctx.status = 200;
|
|
81
|
+
ctx.body = stream;
|
|
82
|
+
addClient(userId, clientId, stream);
|
|
83
|
+
stream.on("close", () => {
|
|
84
|
+
removeClient(userId, clientId);
|
|
85
|
+
});
|
|
86
|
+
stream.on("error", () => {
|
|
87
|
+
removeClient(userId, clientId);
|
|
88
|
+
});
|
|
89
|
+
await next();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
count: {
|
|
93
|
+
handler: async (ctx) => {
|
|
94
|
+
try {
|
|
95
|
+
const userId = ctx.state.currentUser.id;
|
|
96
|
+
const count = await countTotalUnreadMessages(userId);
|
|
97
|
+
ctx.body = { count };
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
list: {
|
|
104
|
+
handler: async (ctx) => {
|
|
105
|
+
var _a, _b;
|
|
106
|
+
const userId = ctx.state.currentUser.id;
|
|
107
|
+
const messagesRepo = app.db.getRepository(import_types.InAppMessagesDefinition.name);
|
|
108
|
+
const { filter = {} } = ((_a = ctx.action) == null ? void 0 : _a.params) ?? {};
|
|
109
|
+
const messageList = await messagesRepo.find({
|
|
110
|
+
limit: 20,
|
|
111
|
+
...((_b = ctx.action) == null ? void 0 : _b.params) ?? {},
|
|
112
|
+
filter: {
|
|
113
|
+
...filter,
|
|
114
|
+
userId
|
|
115
|
+
},
|
|
116
|
+
sort: "-receiveTimestamp"
|
|
117
|
+
});
|
|
118
|
+
ctx.body = { messages: messageList };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|