collabdocchat 2.4.4 → 2.4.5

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 (79) hide show
  1. package/package.json +2 -2
  2. package/scripts/add-button-hover.js +2 -0
  3. package/scripts/add-missing-braces.js +27 -0
  4. package/scripts/add-missing-functions.js +2 -0
  5. package/scripts/add-more-features.js +2 -0
  6. package/scripts/add-user-functions.js +2 -0
  7. package/scripts/auto-publish.js +2 -0
  8. package/scripts/beautify-buttons.js +2 -0
  9. package/scripts/beautify-ui.js +2 -0
  10. package/scripts/check-brackets.js +50 -0
  11. package/scripts/check-encoding.js +2 -0
  12. package/scripts/check-syntax.js +2 -0
  13. package/scripts/delete-orphan-block.js +27 -0
  14. package/scripts/find-buttons.js +2 -0
  15. package/scripts/find-duplicate.js +2 -0
  16. package/scripts/find-extra-brace.js +63 -0
  17. package/scripts/find-sidebar-buttons.js +2 -0
  18. package/scripts/fix-file-end.js +46 -0
  19. package/scripts/fix-help.js +2 -0
  20. package/scripts/fix-issues-step1.js +2 -0
  21. package/scripts/fix-issues-step2.js +2 -0
  22. package/scripts/fix-issues-step3.js +2 -0
  23. package/scripts/fix-issues-step4.js +2 -0
  24. package/scripts/fix-optimized-views.js +2 -0
  25. package/scripts/fix-settings.js +2 -0
  26. package/scripts/fix-syntax-error.js +38 -0
  27. package/scripts/fix-workflow.js +2 -0
  28. package/scripts/refactor-step1.js +2 -0
  29. package/scripts/refactor-step2.js +2 -0
  30. package/scripts/refactor-step3.js +2 -0
  31. package/scripts/refactor-step4.js +2 -0
  32. package/scripts/refactor-step5.js +2 -0
  33. package/scripts/refactor-step6.js +2 -0
  34. package/scripts/refactor-step7.js +2 -0
  35. package/scripts/remove-orphan-code.js +57 -0
  36. package/scripts/update-port-user.js +2 -0
  37. package/scripts/update-port.js +2 -0
  38. package/server/index.js +4 -0
  39. package/server/index.js.bak +97 -0
  40. package/server/models/Document.js +5 -0
  41. package/server/models/KnowledgeBase.js +259 -254
  42. package/server/models/Poll.js +97 -0
  43. package/server/routes/ai.js +391 -327
  44. package/server/routes/audit.js +61 -0
  45. package/server/routes/documents.js +74 -5
  46. package/server/routes/export.js +171 -10
  47. package/server/routes/files.js +27 -4
  48. package/server/routes/knowledge.js +31 -22
  49. package/server/routes/messages.js +142 -0
  50. package/server/routes/polls.js +241 -0
  51. package/server/routes/tasks.js +1 -0
  52. package/server/routes/workflows.js +27 -0
  53. package/server/utils/auditLogger.js +268 -238
  54. package/src/pages/admin-dashboard.js +1431 -335
  55. package/src/pages/admin-dashboard.js.audit-optimize.bak +4134 -0
  56. package/src/pages/admin-dashboard.js.bak +4041 -0
  57. package/src/pages/admin-dashboard.js.broken.bak +4099 -0
  58. package/src/pages/admin-dashboard.js.comprehensive.bak +4099 -0
  59. package/src/pages/admin-dashboard.js.escape.bak +4099 -0
  60. package/src/pages/admin-dashboard.js.final-final-fix.bak +4099 -0
  61. package/src/pages/admin-dashboard.js.final-fix.bak +4099 -0
  62. package/src/pages/admin-dashboard.js.final.bak +4099 -0
  63. package/src/pages/admin-dashboard.js.indent-fix.bak +4099 -0
  64. package/src/pages/admin-dashboard.js.last-fix.bak +4099 -0
  65. package/src/pages/admin-dashboard.js.line595-fix.bak +4099 -0
  66. package/src/pages/admin-dashboard.js.pre-manual-fix.bak +4099 -0
  67. package/src/pages/admin-dashboard.js.syntax.bak +4099 -0
  68. package/src/pages/admin-dashboard.js.test.bak +4099 -0
  69. package/src/pages/optimized-task-detail-original.js +838 -0
  70. package/src/pages/optimized-task-detail.js +324 -22
  71. package/src/pages/optimized-task-detail.js.bak +1162 -0
  72. package/src/pages/poll-detail-enhanced.js +394 -0
  73. package/src/pages/update-poll-display.js +380 -0
  74. package/src/pages/user-dashboard.js +1860 -1006
  75. package/src/services/api.js +326 -265
  76. package/src/services/auth.js +54 -54
  77. package/src/services/websocket.js +88 -80
  78. package/src/pages/simplified-workflows.js +0 -652
  79. package/src/utils/ai-assistant.js +0 -1384
@@ -1,238 +1,268 @@
1
- import AuditLog from '../models/AuditLog.js';
2
-
3
- /**
4
- * 计算文本差异
5
- * @param {string} oldText - 原始文本
6
- * @param {string} newText - 新文本
7
- * @returns {Object} 包含插入和删除操作的对象
8
- */
9
- function calculateTextDiff(oldText = '', newText = '') {
10
- const insertions = [];
11
- const deletions = [];
12
-
13
- // 简单的差异计算算法
14
- // 这里使用基础实现,生产环境可以使用更复杂的diff算法
15
- if (oldText !== newText) {
16
- // 如果完全不同,记录为完全替换
17
- if (oldText.length > 0) {
18
- deletions.push({
19
- position: 0,
20
- content: oldText,
21
- length: oldText.length
22
- });
23
- }
24
-
25
- if (newText.length > 0) {
26
- insertions.push({
27
- position: 0,
28
- content: newText,
29
- length: newText.length
30
- });
31
- }
32
- }
33
-
34
- return { insertions, deletions };
35
- }
36
-
37
- /**
38
- * 记录审计日志
39
- * @param {Object} logData - 日志数据
40
- * @param {Object} req - Express请求对象(可选,用于获取IP等信息)
41
- */
42
- export async function logAuditAction(logData, req = null) {
43
- try {
44
- const auditData = {
45
- action: logData.action,
46
- user: logData.userId,
47
- resourceType: logData.resourceType,
48
- resourceId: logData.resourceId,
49
- resourceTitle: logData.resourceTitle || '',
50
- details: {
51
- oldValue: logData.oldValue,
52
- newValue: logData.newValue,
53
- field: logData.field,
54
- description: logData.description
55
- },
56
- metadata: {
57
- groupId: logData.groupId
58
- }
59
- };
60
-
61
- // 如果是内容编辑,计算文本差异
62
- if (logData.action === 'content_edit' && logData.oldValue && logData.newValue) {
63
- auditData.changes = calculateTextDiff(logData.oldValue, logData.newValue);
64
- }
65
-
66
- // 从请求中提取元数据
67
- if (req) {
68
- auditData.metadata.ipAddress = req.ip || req.connection.remoteAddress;
69
- auditData.metadata.userAgent = req.get('User-Agent');
70
- }
71
-
72
- const auditLog = new AuditLog(auditData);
73
- await auditLog.save();
74
-
75
- return auditLog;
76
- } catch (error) {
77
- console.error('记录审计日志失败:', error);
78
- // 审计日志记录失败不应该影响主业务逻辑
79
- return null;
80
- }
81
- }
82
-
83
- /**
84
- * 批量记录审计日志
85
- * @param {Array} logDataArray - 日志数据数组
86
- * @param {Object} req - Express请求对象
87
- */
88
- export async function logMultipleAuditActions(logDataArray, req = null) {
89
- const promises = logDataArray.map(logData => logAuditAction(logData, req));
90
- return Promise.allSettled(promises);
91
- }
92
-
93
- /**
94
- * 查询审计日志
95
- * @param {Object} filters - 查询过滤条件
96
- * @param {Object} options - 查询选项(分页、排序等)
97
- */
98
- export async function queryAuditLogs(filters = {}, options = {}) {
99
- try {
100
- const {
101
- page = 1,
102
- limit = 50,
103
- sortBy = 'createdAt',
104
- sortOrder = -1
105
- } = options;
106
-
107
- const query = {};
108
-
109
- // 构建查询条件
110
- if (filters.userId) {
111
- query.user = filters.userId;
112
- }
113
-
114
- if (filters.resourceId) {
115
- query.resourceId = filters.resourceId;
116
- }
117
-
118
- if (filters.resourceType) {
119
- query.resourceType = filters.resourceType;
120
- }
121
-
122
- if (filters.action) {
123
- query.action = filters.action;
124
- }
125
-
126
- if (filters.groupId) {
127
- query['metadata.groupId'] = filters.groupId;
128
- }
129
-
130
- if (filters.startDate && filters.endDate) {
131
- query.createdAt = {
132
- $gte: new Date(filters.startDate),
133
- $lte: new Date(filters.endDate)
134
- };
135
- } else if (filters.startDate) {
136
- query.createdAt = { $gte: new Date(filters.startDate) };
137
- } else if (filters.endDate) {
138
- query.createdAt = { $lte: new Date(filters.endDate) };
139
- }
140
-
141
- const skip = (page - 1) * limit;
142
-
143
- const [logs, total] = await Promise.all([
144
- AuditLog.find(query)
145
- .populate('user', 'username email avatar')
146
- .populate('metadata.groupId', 'name')
147
- .sort({ [sortBy]: sortOrder })
148
- .skip(skip)
149
- .limit(limit)
150
- .lean(),
151
- AuditLog.countDocuments(query)
152
- ]);
153
-
154
- return {
155
- logs,
156
- pagination: {
157
- page,
158
- limit,
159
- total,
160
- pages: Math.ceil(total / limit)
161
- }
162
- };
163
- } catch (error) {
164
- console.error('查询审计日志失败:', error);
165
- throw new Error('查询审计日志失败');
166
- }
167
- }
168
-
169
- /**
170
- * 获取用户活动统计
171
- * @param {string} userId - 用户ID
172
- * @param {Object} timeRange - 时间范围
173
- */
174
- export async function getUserActivityStats(userId, timeRange = {}) {
175
- try {
176
- const { startDate, endDate } = timeRange;
177
- const matchStage = { user: userId };
178
-
179
- if (startDate && endDate) {
180
- matchStage.createdAt = {
181
- $gte: new Date(startDate),
182
- $lte: new Date(endDate)
183
- };
184
- }
185
-
186
- const stats = await AuditLog.aggregate([
187
- { $match: matchStage },
188
- {
189
- $group: {
190
- _id: '$action',
191
- count: { $sum: 1 },
192
- lastActivity: { $max: '$createdAt' }
193
- }
194
- },
195
- { $sort: { count: -1 } }
196
- ]);
197
-
198
- const totalActions = stats.reduce((sum, stat) => sum + stat.count, 0);
199
-
200
- return {
201
- totalActions,
202
- actionBreakdown: stats,
203
- timeRange
204
- };
205
- } catch (error) {
206
- console.error('获取用户活动统计失败:', error);
207
- throw new Error('获取用户活动统计失败');
208
- }
209
- }
210
-
211
- /**
212
- * 获取文档编辑历史摘要
213
- * @param {string} documentId - 文档ID
214
- * @param {number} limit - 返回记录数限制
215
- */
216
- export async function getDocumentEditHistory(documentId, limit = 20) {
217
- try {
218
- const history = await AuditLog.find({
219
- resourceId: documentId,
220
- resourceType: 'document',
221
- action: { $in: ['content_edit', 'title_edit', 'document_update'] }
222
- })
223
- .populate('user', 'username avatar')
224
- .sort({ createdAt: -1 })
225
- .limit(limit)
226
- .lean();
227
-
228
- return history;
229
- } catch (error) {
230
- console.error('获取文档编辑历史失败:', error);
231
- throw new Error('获取文档编辑历史失败');
232
- }
233
- }
234
-
235
-
236
-
237
-
238
-
1
+ import AuditLog from '../models/AuditLog.js';
2
+
3
+ /**
4
+ * 去除HTML标签,只保留纯文本
5
+ * @param {string} html - HTML内容
6
+ * @returns {string} 纯文本内容
7
+ */
8
+ function stripHtmlTags(html) {
9
+ if (!html || typeof html !== 'string') return '';
10
+
11
+ // 移除HTML标签
12
+ let text = html.replace(/<[^>]*>/g, '');
13
+
14
+ // 解码HTML实体
15
+ text = text
16
+ .replace(/&nbsp;/g, ' ')
17
+ .replace(/&lt;/g, '<')
18
+ .replace(/&gt;/g, '>')
19
+ .replace(/&amp;/g, '&')
20
+ .replace(/&quot;/g, '"')
21
+ .replace(/&#39;/g, "'");
22
+
23
+ // 移除多余的空白字符
24
+ text = text.trim();
25
+
26
+ return text;
27
+ }
28
+
29
+ /**
30
+ * 计算文本差异
31
+ * @param {string} oldText - 原始文本
32
+ * @param {string} newText - 新文本
33
+ * @returns {Object} 包含插入和删除操作的对象
34
+ */
35
+ function calculateTextDiff(oldText = '', newText = '') {
36
+ // 去除HTML标签,只比较纯文本
37
+ const cleanOldText = stripHtmlTags(oldText);
38
+ const cleanNewText = stripHtmlTags(newText);
39
+
40
+ const insertions = [];
41
+ const deletions = [];
42
+
43
+ // 简单的差异计算算法
44
+ // 这里使用基础实现,生产环境可以使用更复杂的diff算法
45
+ if (cleanOldText !== cleanNewText) {
46
+ // 如果完全不同,记录为完全替换
47
+ if (cleanOldText.length > 0) {
48
+ deletions.push({
49
+ position: 0,
50
+ content: cleanOldText,
51
+ length: cleanOldText.length
52
+ });
53
+ }
54
+
55
+ if (cleanNewText.length > 0) {
56
+ insertions.push({
57
+ position: 0,
58
+ content: cleanNewText,
59
+ length: cleanNewText.length
60
+ });
61
+ }
62
+ }
63
+
64
+ return { insertions, deletions };
65
+ }
66
+
67
+ /**
68
+ * 记录审计日志
69
+ * @param {Object} logData - 日志数据
70
+ * @param {Object} req - Express请求对象(可选,用于获取IP等信息)
71
+ */
72
+ export async function logAuditAction(logData, req = null) {
73
+ try {
74
+ const auditData = {
75
+ action: logData.action,
76
+ user: logData.userId,
77
+ resourceType: logData.resourceType,
78
+ resourceId: logData.resourceId,
79
+ resourceTitle: logData.resourceTitle || '',
80
+ details: {
81
+ oldValue: stripHtmlTags(logData.oldValue),
82
+ newValue: stripHtmlTags(logData.newValue),
83
+ field: logData.field,
84
+ description: logData.description
85
+ },
86
+ metadata: {
87
+ groupId: logData.groupId
88
+ }
89
+ };
90
+
91
+ // 如果是内容编辑,计算文本差异
92
+ if (logData.action === 'content_edit' && logData.oldValue && logData.newValue) {
93
+ auditData.changes = calculateTextDiff(logData.oldValue, logData.newValue);
94
+ }
95
+
96
+ // 从请求中提取元数据
97
+ if (req) {
98
+ auditData.metadata.ipAddress = req.ip || req.connection.remoteAddress;
99
+ auditData.metadata.userAgent = req.get('User-Agent');
100
+ }
101
+
102
+ const auditLog = new AuditLog(auditData);
103
+ await auditLog.save();
104
+
105
+ return auditLog;
106
+ } catch (error) {
107
+ console.error('记录审计日志失败:', error);
108
+ // 审计日志记录失败不应该影响主业务逻辑
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * 批量记录审计日志
115
+ * @param {Array} logDataArray - 日志数据数组
116
+ * @param {Object} req - Express请求对象
117
+ */
118
+ export async function logMultipleAuditActions(logDataArray, req = null) {
119
+ const promises = logDataArray.map(logData => logAuditAction(logData, req));
120
+ return Promise.allSettled(promises);
121
+ }
122
+
123
+ /**
124
+ * 查询审计日志
125
+ * @param {Object} filters - 查询过滤条件
126
+ * @param {Object} options - 查询选项(分页、排序等)
127
+ */
128
+ export async function queryAuditLogs(filters = {}, options = {}) {
129
+ try {
130
+ const {
131
+ page = 1,
132
+ limit = 50,
133
+ sortBy = 'createdAt',
134
+ sortOrder = -1
135
+ } = options;
136
+
137
+ const query = {};
138
+
139
+ // 构建查询条件
140
+ if (filters.userId) {
141
+ query.user = filters.userId;
142
+ }
143
+
144
+ if (filters.resourceId) {
145
+ query.resourceId = filters.resourceId;
146
+ }
147
+
148
+ if (filters.resourceType) {
149
+ query.resourceType = filters.resourceType;
150
+ }
151
+
152
+ if (filters.action) {
153
+ query.action = filters.action;
154
+ }
155
+
156
+ if (filters.groupId) {
157
+ query['metadata.groupId'] = filters.groupId;
158
+ }
159
+
160
+ if (filters.startDate && filters.endDate) {
161
+ query.createdAt = {
162
+ $gte: new Date(filters.startDate),
163
+ $lte: new Date(filters.endDate)
164
+ };
165
+ } else if (filters.startDate) {
166
+ query.createdAt = { $gte: new Date(filters.startDate) };
167
+ } else if (filters.endDate) {
168
+ query.createdAt = { $lte: new Date(filters.endDate) };
169
+ }
170
+
171
+ const skip = (page - 1) * limit;
172
+
173
+ const [logs, total] = await Promise.all([
174
+ AuditLog.find(query)
175
+ .populate('user', 'username email avatar')
176
+ .populate('metadata.groupId', 'name')
177
+ .sort({ [sortBy]: sortOrder })
178
+ .skip(skip)
179
+ .limit(limit)
180
+ .lean(),
181
+ AuditLog.countDocuments(query)
182
+ ]);
183
+
184
+ return {
185
+ logs,
186
+ pagination: {
187
+ page,
188
+ limit,
189
+ total,
190
+ pages: Math.ceil(total / limit)
191
+ }
192
+ };
193
+ } catch (error) {
194
+ console.error('查询审计日志失败:', error);
195
+ throw new Error('查询审计日志失败');
196
+ }
197
+ }
198
+
199
+ /**
200
+ * 获取用户活动统计
201
+ * @param {string} userId - 用户ID
202
+ * @param {Object} timeRange - 时间范围
203
+ */
204
+ export async function getUserActivityStats(userId, timeRange = {}) {
205
+ try {
206
+ const { startDate, endDate } = timeRange;
207
+ const matchStage = { user: userId };
208
+
209
+ if (startDate && endDate) {
210
+ matchStage.createdAt = {
211
+ $gte: new Date(startDate),
212
+ $lte: new Date(endDate)
213
+ };
214
+ }
215
+
216
+ const stats = await AuditLog.aggregate([
217
+ { $match: matchStage },
218
+ {
219
+ $group: {
220
+ _id: '$action',
221
+ count: { $sum: 1 },
222
+ lastActivity: { $max: '$createdAt' }
223
+ }
224
+ },
225
+ { $sort: { count: -1 } }
226
+ ]);
227
+
228
+ const totalActions = stats.reduce((sum, stat) => sum + stat.count, 0);
229
+
230
+ return {
231
+ totalActions,
232
+ actionBreakdown: stats,
233
+ timeRange
234
+ };
235
+ } catch (error) {
236
+ console.error('获取用户活动统计失败:', error);
237
+ throw new Error('获取用户活动统计失败');
238
+ }
239
+ }
240
+
241
+ /**
242
+ * 获取文档编辑历史摘要
243
+ * @param {string} documentId - 文档ID
244
+ * @param {number} limit - 返回记录数限制
245
+ */
246
+ export async function getDocumentEditHistory(documentId, limit = 20) {
247
+ try {
248
+ const history = await AuditLog.find({
249
+ resourceId: documentId,
250
+ resourceType: 'document',
251
+ action: { $in: ['content_edit', 'title_edit', 'document_update'] }
252
+ })
253
+ .populate('user', 'username avatar')
254
+ .sort({ createdAt: -1 })
255
+ .limit(limit)
256
+ .lean();
257
+
258
+ return history;
259
+ } catch (error) {
260
+ console.error('获取文档编辑历史失败:', error);
261
+ throw new Error('获取文档编辑历史失败');
262
+ }
263
+ }
264
+
265
+
266
+
267
+
268
+