@tachybase/module-user 1.3.25 → 1.5.0
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/dist/client/UserNicknameField.d.ts +1 -0
- package/dist/client/UserStatusField.d.ts +1 -0
- package/dist/client/UserStatusHistories.d.ts +1 -0
- package/dist/client/UserStatusManagement.d.ts +1 -0
- package/dist/client/index.js +2 -2
- package/dist/client/locale.d.ts +1 -1
- package/dist/client/schemas/userStatusHistories.d.ts +120 -0
- package/dist/client/schemas/userStatuses.d.ts +104 -0
- package/dist/client/schemas/users.d.ts +94 -0
- package/dist/externalVersion.js +3 -3
- package/dist/locale/en-US.json +38 -1
- package/dist/locale/zh-CN.json +38 -1
- package/dist/server/collections/userStatusHistories.d.ts +2 -0
- package/dist/server/collections/userStatusHistories.js +180 -0
- package/dist/server/collections/userStatuses.d.ts +2 -0
- package/dist/server/collections/userStatuses.js +144 -0
- package/dist/server/collections/users.js +103 -0
- package/dist/server/migrations/20251027170000-add-user-status-fields.d.ts +6 -0
- package/dist/server/migrations/20251027170000-add-user-status-fields.js +232 -0
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.js +108 -0
- package/package.json +5 -5
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var add_user_status_fields_exports = {};
|
|
19
|
+
__export(add_user_status_fields_exports, {
|
|
20
|
+
default: () => AddUserStatusFieldsMigration
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(add_user_status_fields_exports);
|
|
23
|
+
var import_server = require("@tego/server");
|
|
24
|
+
class AddUserStatusFieldsMigration extends import_server.Migration {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.appVersion = "<1.4.0";
|
|
28
|
+
}
|
|
29
|
+
async up() {
|
|
30
|
+
const Field = this.context.db.getRepository("fields");
|
|
31
|
+
const statusFieldExists = await Field.count({
|
|
32
|
+
filter: {
|
|
33
|
+
name: "status",
|
|
34
|
+
collectionName: "users"
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
if (!statusFieldExists) {
|
|
38
|
+
await Field.create({
|
|
39
|
+
values: {
|
|
40
|
+
name: "status",
|
|
41
|
+
collectionName: "users",
|
|
42
|
+
type: "string",
|
|
43
|
+
defaultValue: "active",
|
|
44
|
+
comment: "\u7528\u6237\u72B6\u6001\uFF1Aactive-\u6B63\u5E38, pending-\u5F85\u5BA1\u6838, locked-\u9501\u5B9A, disabled-\u505C\u7528",
|
|
45
|
+
uiSchema: {
|
|
46
|
+
type: "string",
|
|
47
|
+
title: '{{t("Status")}}',
|
|
48
|
+
"x-component": "Select",
|
|
49
|
+
"x-component-props": {
|
|
50
|
+
fieldNames: {
|
|
51
|
+
label: "title",
|
|
52
|
+
value: "key"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const statusExpireAtFieldExists = await Field.count({
|
|
60
|
+
filter: {
|
|
61
|
+
name: "statusExpireAt",
|
|
62
|
+
collectionName: "users"
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
if (!statusExpireAtFieldExists) {
|
|
66
|
+
await Field.create({
|
|
67
|
+
values: {
|
|
68
|
+
name: "statusExpireAt",
|
|
69
|
+
collectionName: "users",
|
|
70
|
+
type: "date",
|
|
71
|
+
comment: "\u72B6\u6001\u8FC7\u671F\u65F6\u95F4\uFF0Cnull\u8868\u793A\u6C38\u4E45",
|
|
72
|
+
uiSchema: {
|
|
73
|
+
type: "string",
|
|
74
|
+
title: '{{t("Status Expire At")}}',
|
|
75
|
+
"x-component": "DatePicker",
|
|
76
|
+
"x-component-props": {
|
|
77
|
+
showTime: true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const previousStatusFieldExists = await Field.count({
|
|
84
|
+
filter: {
|
|
85
|
+
name: "previousStatus",
|
|
86
|
+
collectionName: "users"
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!previousStatusFieldExists) {
|
|
90
|
+
await Field.create({
|
|
91
|
+
values: {
|
|
92
|
+
name: "previousStatus",
|
|
93
|
+
collectionName: "users",
|
|
94
|
+
type: "string",
|
|
95
|
+
comment: "\u539F\u72B6\u6001\uFF0C\u7528\u4E8E\u72B6\u6001\u8FC7\u671F\u540E\u81EA\u52A8\u6062\u590D",
|
|
96
|
+
uiSchema: {
|
|
97
|
+
type: "string",
|
|
98
|
+
title: '{{t("Previous Status")}}',
|
|
99
|
+
"x-component": "Select",
|
|
100
|
+
"x-component-props": {
|
|
101
|
+
fieldNames: {
|
|
102
|
+
label: "title",
|
|
103
|
+
value: "key"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const statusReasonFieldExists = await Field.count({
|
|
111
|
+
filter: {
|
|
112
|
+
name: "statusReason",
|
|
113
|
+
collectionName: "users"
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (!statusReasonFieldExists) {
|
|
117
|
+
await Field.create({
|
|
118
|
+
values: {
|
|
119
|
+
name: "statusReason",
|
|
120
|
+
collectionName: "users",
|
|
121
|
+
type: "text",
|
|
122
|
+
comment: "\u72B6\u6001\u53D8\u66F4\u539F\u56E0\u8BF4\u660E",
|
|
123
|
+
uiSchema: {
|
|
124
|
+
type: "string",
|
|
125
|
+
title: '{{t("Status Reason")}}',
|
|
126
|
+
"x-component": "Input.TextArea"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const statusInfoFieldExists = await Field.count({
|
|
132
|
+
filter: {
|
|
133
|
+
name: "statusInfo",
|
|
134
|
+
collectionName: "users"
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (!statusInfoFieldExists) {
|
|
138
|
+
await Field.create({
|
|
139
|
+
values: {
|
|
140
|
+
name: "statusInfo",
|
|
141
|
+
collectionName: "users",
|
|
142
|
+
type: "belongsTo",
|
|
143
|
+
target: "userStatuses",
|
|
144
|
+
foreignKey: "status",
|
|
145
|
+
targetKey: "key",
|
|
146
|
+
uiSchema: {
|
|
147
|
+
type: "object",
|
|
148
|
+
title: '{{t("Status")}}',
|
|
149
|
+
"x-component": "AssociationField",
|
|
150
|
+
"x-component-props": {
|
|
151
|
+
fieldNames: {
|
|
152
|
+
label: "title",
|
|
153
|
+
value: "key"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const previousStatusInfoFieldExists = await Field.count({
|
|
161
|
+
filter: {
|
|
162
|
+
name: "previousStatusInfo",
|
|
163
|
+
collectionName: "users"
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
if (!previousStatusInfoFieldExists) {
|
|
167
|
+
await Field.create({
|
|
168
|
+
values: {
|
|
169
|
+
name: "previousStatusInfo",
|
|
170
|
+
collectionName: "users",
|
|
171
|
+
type: "belongsTo",
|
|
172
|
+
target: "userStatuses",
|
|
173
|
+
foreignKey: "previousStatus",
|
|
174
|
+
targetKey: "key",
|
|
175
|
+
uiSchema: {
|
|
176
|
+
type: "object",
|
|
177
|
+
title: '{{t("Previous Status")}}',
|
|
178
|
+
"x-component": "AssociationField",
|
|
179
|
+
"x-component-props": {
|
|
180
|
+
fieldNames: {
|
|
181
|
+
label: "title",
|
|
182
|
+
value: "key"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const statusHistoriesFieldExists = await Field.count({
|
|
190
|
+
filter: {
|
|
191
|
+
name: "statusHistories",
|
|
192
|
+
collectionName: "users"
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (!statusHistoriesFieldExists) {
|
|
196
|
+
await Field.create({
|
|
197
|
+
values: {
|
|
198
|
+
name: "statusHistories",
|
|
199
|
+
collectionName: "users",
|
|
200
|
+
type: "hasMany",
|
|
201
|
+
target: "userStatusHistories",
|
|
202
|
+
foreignKey: "userId",
|
|
203
|
+
uiSchema: {
|
|
204
|
+
type: "array",
|
|
205
|
+
title: '{{t("Status History")}}',
|
|
206
|
+
"x-component": "AssociationField"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async down() {
|
|
213
|
+
const Field = this.context.db.getRepository("fields");
|
|
214
|
+
const fieldsToRemove = [
|
|
215
|
+
"status",
|
|
216
|
+
"statusExpireAt",
|
|
217
|
+
"previousStatus",
|
|
218
|
+
"statusReason",
|
|
219
|
+
"statusInfo",
|
|
220
|
+
"previousStatusInfo",
|
|
221
|
+
"statusHistories"
|
|
222
|
+
];
|
|
223
|
+
for (const fieldName of fieldsToRemove) {
|
|
224
|
+
await Field.destroy({
|
|
225
|
+
filter: {
|
|
226
|
+
name: fieldName,
|
|
227
|
+
collectionName: "users"
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
package/dist/server/server.d.ts
CHANGED
package/dist/server/server.js
CHANGED
|
@@ -139,6 +139,48 @@ class PluginUsersServer extends import_server.Plugin {
|
|
|
139
139
|
name: `pm.${this.name}.*`,
|
|
140
140
|
actions: ["users:listExcludeRole", "users:list"]
|
|
141
141
|
});
|
|
142
|
+
this.app.acl.registerSnippet({
|
|
143
|
+
name: `pm.users.statuses`,
|
|
144
|
+
actions: ["userStatuses:*", "userStatusHistories:*"]
|
|
145
|
+
});
|
|
146
|
+
this.app.acl.addFixedParams("userStatuses", "destroy", () => {
|
|
147
|
+
return {
|
|
148
|
+
filter: {
|
|
149
|
+
"isSystemDefined.$ne": true
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
this.app.acl.addFixedParams("userStatuses", "update", () => {
|
|
154
|
+
return {
|
|
155
|
+
filter: {
|
|
156
|
+
"isSystemDefined.$ne": true
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
this.app.acl.addFixedParams("userStatusHistories", "destroy", () => {
|
|
161
|
+
return {
|
|
162
|
+
filter: {
|
|
163
|
+
id: -1
|
|
164
|
+
// 永远不匹配任何记录
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
this.app.acl.addFixedParams("userStatusHistories", "update", () => {
|
|
169
|
+
return {
|
|
170
|
+
filter: {
|
|
171
|
+
id: -1
|
|
172
|
+
// 永远不匹配任何记录
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
this.app.acl.addFixedParams("userStatusHistories", "create", () => {
|
|
177
|
+
return {
|
|
178
|
+
filter: {
|
|
179
|
+
id: -1
|
|
180
|
+
// 永远不匹配任何记录
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
});
|
|
142
184
|
}
|
|
143
185
|
async load() {
|
|
144
186
|
await this.importCollections((0, import_node_path.resolve)(__dirname, "collections"));
|
|
@@ -152,6 +194,9 @@ class PluginUsersServer extends import_server.Plugin {
|
|
|
152
194
|
if (!import_node_worker_threads.isMainThread) {
|
|
153
195
|
return;
|
|
154
196
|
}
|
|
197
|
+
this.app.on("afterLoad", async () => {
|
|
198
|
+
await this.initSystemStatuses();
|
|
199
|
+
});
|
|
155
200
|
this.app.resourcer.use(
|
|
156
201
|
async (ctx, next) => {
|
|
157
202
|
await next();
|
|
@@ -220,4 +265,67 @@ class PluginUsersServer extends import_server.Plugin {
|
|
|
220
265
|
await repo.db2cm("users");
|
|
221
266
|
}
|
|
222
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* 初始化系统内置状态
|
|
270
|
+
*/
|
|
271
|
+
async initSystemStatuses() {
|
|
272
|
+
const systemStatuses = [
|
|
273
|
+
{
|
|
274
|
+
key: "active",
|
|
275
|
+
title: '{{t("Active")}}',
|
|
276
|
+
color: "green",
|
|
277
|
+
allowLogin: true,
|
|
278
|
+
loginErrorMessage: null,
|
|
279
|
+
isSystemDefined: true,
|
|
280
|
+
packageName: "@tachybase/module-user",
|
|
281
|
+
description: '{{t("Normal active user")}}',
|
|
282
|
+
sort: 1,
|
|
283
|
+
config: {}
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
key: "pending",
|
|
287
|
+
title: '{{t("Pending")}}',
|
|
288
|
+
color: "orange",
|
|
289
|
+
allowLogin: false,
|
|
290
|
+
loginErrorMessage: '{{t("Your account is under review, please wait for administrator approval")}}',
|
|
291
|
+
isSystemDefined: true,
|
|
292
|
+
packageName: "@tachybase/module-user",
|
|
293
|
+
description: '{{t("User waiting for approval")}}',
|
|
294
|
+
sort: 2,
|
|
295
|
+
config: {}
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
key: "disabled",
|
|
299
|
+
title: '{{t("Disabled")}}',
|
|
300
|
+
color: "gray",
|
|
301
|
+
allowLogin: false,
|
|
302
|
+
loginErrorMessage: '{{t("Your account has been disabled, please contact administrator if you have any questions")}}',
|
|
303
|
+
isSystemDefined: true,
|
|
304
|
+
packageName: "@tachybase/module-user",
|
|
305
|
+
description: '{{t("Manually disabled by administrator")}}',
|
|
306
|
+
sort: 3,
|
|
307
|
+
config: {}
|
|
308
|
+
}
|
|
309
|
+
];
|
|
310
|
+
const statusRepo = this.db.getRepository("userStatuses");
|
|
311
|
+
if (!statusRepo) {
|
|
312
|
+
this.app.logger.warn("userStatuses repository not found");
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
for (const status of systemStatuses) {
|
|
316
|
+
try {
|
|
317
|
+
const existing = await statusRepo.findOne({
|
|
318
|
+
filter: { key: status.key }
|
|
319
|
+
});
|
|
320
|
+
if (!existing) {
|
|
321
|
+
await statusRepo.create({
|
|
322
|
+
values: status
|
|
323
|
+
});
|
|
324
|
+
this.app.logger.info(`Created system status: ${status.key}`);
|
|
325
|
+
}
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this.app.logger.error(`Failed to create system status ${status.key}:`, error);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
223
331
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/module-user",
|
|
3
3
|
"displayName": "Users",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "Provides basic user model, as well as created by and updated by fields.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"Users & permissions"
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"@types/jsonwebtoken": "^8.5.9",
|
|
18
18
|
"antd": "5.22.5",
|
|
19
19
|
"jsonwebtoken": "^8.5.1",
|
|
20
|
-
"react-i18next": "
|
|
21
|
-
"@tachybase/client": "1.
|
|
22
|
-
"@tachybase/module-
|
|
23
|
-
"@tachybase/module-
|
|
20
|
+
"react-i18next": "16.2.1",
|
|
21
|
+
"@tachybase/client": "1.5.0",
|
|
22
|
+
"@tachybase/module-acl": "1.5.0",
|
|
23
|
+
"@tachybase/module-auth": "1.5.0"
|
|
24
24
|
},
|
|
25
25
|
"description.zh-CN": "提供了基础的用户模型,以及创建人和最后更新人字段。",
|
|
26
26
|
"displayName.zh-CN": "用户",
|