@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.
Files changed (55) hide show
  1. package/LICENSE.txt +159 -0
  2. package/README.md +1 -0
  3. package/client.d.ts +2 -0
  4. package/client.js +1 -0
  5. package/dist/client/MessageManagerProvider.d.ts +10 -0
  6. package/dist/client/components/ContentConfigForm.d.ts +12 -0
  7. package/dist/client/components/Inbox.d.ts +18 -0
  8. package/dist/client/components/InboxContent.d.ts +10 -0
  9. package/dist/client/components/MessageConfigForm.d.ts +12 -0
  10. package/dist/client/components/MessageList.d.ts +10 -0
  11. package/dist/client/components/UsersAddition.d.ts +10 -0
  12. package/dist/client/components/UsersSelect.d.ts +18 -0
  13. package/dist/client/components/hooks/useChat.d.ts +36 -0
  14. package/dist/client/index.d.ts +15 -0
  15. package/dist/client/index.js +24 -0
  16. package/dist/client/observables/channel.d.ts +37 -0
  17. package/dist/client/observables/inbox.d.ts +11 -0
  18. package/dist/client/observables/index.d.ts +13 -0
  19. package/dist/client/observables/message.d.ts +33 -0
  20. package/dist/client/observables/sse.d.ts +5 -0
  21. package/dist/client/observables/user.d.ts +11 -0
  22. package/dist/client/utils.d.ts +11 -0
  23. package/dist/externalVersion.js +29 -0
  24. package/dist/index.d.ts +10 -0
  25. package/dist/index.js +48 -0
  26. package/dist/locale/en-US.json +22 -0
  27. package/dist/locale/index.d.ts +12 -0
  28. package/dist/locale/index.js +55 -0
  29. package/dist/locale/zh-CN.json +21 -0
  30. package/dist/server/InAppNotificationChannel.d.ts +41 -0
  31. package/dist/server/InAppNotificationChannel.js +162 -0
  32. package/dist/server/collections/messages.d.ts +10 -0
  33. package/dist/server/collections/messages.js +33 -0
  34. package/dist/server/defineMyInAppChannels.d.ts +12 -0
  35. package/dist/server/defineMyInAppChannels.js +159 -0
  36. package/dist/server/defineMyInAppMessages.d.ts +15 -0
  37. package/dist/server/defineMyInAppMessages.js +123 -0
  38. package/dist/server/index.d.ts +9 -0
  39. package/dist/server/index.js +42 -0
  40. package/dist/server/parseUserSelectionConf.d.ts +10 -0
  41. package/dist/server/parseUserSelectionConf.js +51 -0
  42. package/dist/server/plugin.d.ts +19 -0
  43. package/dist/server/plugin.js +72 -0
  44. package/dist/types/channels.d.ts +18 -0
  45. package/dist/types/channels.js +93 -0
  46. package/dist/types/index.d.ts +64 -0
  47. package/dist/types/index.js +62 -0
  48. package/dist/types/messages.d.ts +10 -0
  49. package/dist/types/messages.js +129 -0
  50. package/dist/types/sse.d.ts +20 -0
  51. package/dist/types/sse.js +24 -0
  52. package/package.json +25 -0
  53. package/server.d.ts +2 -0
  54. package/server.js +1 -0
  55. 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
+ }