Skip to content

Commit 9b14f77

Browse files
committed
feat: Add user_sub resource and integrate with existing user management system
1 parent 575a792 commit 9b14f77

File tree

8 files changed

+219
-28
lines changed

8 files changed

+219
-28
lines changed

db.sqlite

48 KB
Binary file not shown.

dev-demo/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import apartmentBuyersResource from './resources/apartment_buyers.js';
99
import auditLogResource from './resources/audit_log.js';
1010
import descriptionImageResource from './resources/description_image.js';
1111
import usersResource from './resources/users.js';
12+
import userSubResource from './resources/user_sub.js';
1213
// import gameResource from './resources/game.js';
1314
// import gamesUsersResource from './resources/games_users.js';
1415
// import gamesResource from './resources/games.js';
@@ -209,6 +210,7 @@ export const admin = new AdminForth({
209210
clinicsResource,
210211
providersResource,
211212
apiKeysResource,
213+
userSubResource,
212214
// gamesResource,
213215
// gamesUsersResource,
214216
// gameResource,
@@ -294,7 +296,7 @@ export const admin = new AdminForth({
294296
label: 'Translations',
295297
icon: 'material-symbols:translate',
296298
resourceId: 'translations',
297-
}
299+
},
298300
]
299301
},
300302
{

dev-demo/resources/apartments.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import UploadPlugin from "../../plugins/adminforth-upload";
1010
import ImportExportPlugin from "../../plugins/adminforth-import-export/index.js";
1111
import { v1 as uuid } from "uuid";
1212
import RichEditorPlugin from "../../plugins/adminforth-rich-editor";
13+
import ListInPlaceEditPlugin from "../../plugins/adminforth-list-in-place-edit";
1314
import { AdminForthResourceInput } from "../../adminforth";
1415
import CompletionAdapterOpenAIChatGPT from "../../adapters/adminforth-completion-adapter-open-ai-chat-gpt/index.js";
15-
16+
import InlineCreatePlugin from "../../plugins/adminforth-inline-create";
1617
const demoChecker = async ({ record, adminUser, resource }) => {
1718
if (adminUser.dbUser.role !== "superadmin") {
1819
return { ok: false, error: "You can't do this on demo.adminforth.dev" };
@@ -190,7 +191,8 @@ export default {
190191
showIn: {create: true, edit: true, filter: true, show: true},
191192
allowMinMaxQuery: true, // use better experience for filtering e.g. date range, set it only if you have index on this column or if there will be low number of rows
192193
editingNote: "Price is in USD", // you can appear note on editing or creating page
193-
editReadonly: true, // you can set field to be readonly on edit page
194+
// editReadonly: true, // you can set field to be readonly on edit page
195+
type: AdminForthDataTypes.DECIMAL,
194196

195197
},
196198
{
@@ -298,21 +300,32 @@ export default {
298300
preview: {
299301
// Used to display preview (if it is image) in list and show views
300302
// previewUrl: ({s3Path}) => `https://tmpbucket-adminforth.s3.eu-central-1.amazonaws.com/${s3Path}`,
301-
showInList: true,
302-
maxWidth: "200px",
303+
// showInList: true,
304+
// maxWidth: "200px",
305+
maxWidth: "40px",
306+
maxListWidth: "300px",
307+
minWidth: "200px",
308+
// minListWidth: "100px",
309+
// minShowWidth: "200px",
310+
303311
},
304312
}),
305313
]
306314
: []),
307315
new ImportExportPlugin({}),
308-
new TextCompletePlugin({
309-
fieldName: "title",
310-
expert: {
311-
debounceTime: 250,
312-
},
313-
adapter: new CompletionAdapterOpenAIChatGPT({
314-
openAiApiKey: process.env.OPENAI_API_KEY as string,
315-
}),
316+
// new TextCompletePlugin({
317+
// fieldName: "title",
318+
// expert: {
319+
// debounceTime: 250,
320+
// },
321+
// adapter: new CompletionAdapterOpenAIChatGPT({
322+
// openAiApiKey: process.env.OPENAI_API_KEY as string,
323+
// }),
324+
// }),
325+
new InlineCreatePlugin({
326+
}),
327+
new ListInPlaceEditPlugin({
328+
columns: ["title", "price", "number_of_rooms", "description", "listed", "room_sizes"]
316329
}),
317330
// new TextCompletePlugin({
318331
// openAiApiKey: process.env.OPENAI_API_KEY as string,

dev-demo/resources/api_keys.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ export default {
3030
{
3131
name: 'owner',
3232
type: AdminForthDataTypes.STRING,
33-
enum: [
34-
{
35-
value: 'clinic',
36-
label: 'Clinic',
37-
},
38-
{
39-
value: 'provider',
40-
label: 'Provider',
41-
},
42-
],
33+
// enum: [
34+
// {
35+
// value: 'clinic',
36+
// label: 'Clinic',
37+
// },
38+
// {
39+
// value: 'provider',
40+
// label: 'Provider',
41+
// },
42+
// ],
4343
showIn: { create: false, edit: false },
4444
},
4545
{

dev-demo/resources/clinics.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { AdminForthDataTypes, AdminForthResourceInput } from "../../adminforth";
22
import { v1 as uuid } from "uuid";
3+
import ImportExport from "../../plugins/adminforth-import-export";
4+
35

46
export default {
57
dataSource: 'maindb',
@@ -23,11 +25,15 @@ export default {
2325
},
2426
{
2527
name: 'name',
26-
type: AdminForthDataTypes.STRING,
28+
type: AdminForthDataTypes.TEXT,
2729
required: true,
2830
maxLength: 255,
31+
2932
},
3033
],
31-
plugins: [],
34+
plugins: [
35+
new ImportExport({
36+
}),
37+
],
3238
options: {},
3339
} as AdminForthResourceInput;

dev-demo/resources/user_sub.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import AdminForth, {
2+
AdminForthDataTypes,
3+
AdminForthResource,
4+
AdminForthResourceColumn,
5+
AdminForthResourceInput,
6+
AdminUser,
7+
} from "../../adminforth/dist";
8+
import ForeignInlineListPlugin from "../../plugins/adminforth-foreign-inline-list";
9+
import OpenSignupPlugin from "../../plugins/adminforth-open-signup";
10+
import TwoFactorsAuthPlugin from "../../plugins/adminforth-two-factors-auth";
11+
import EmailResetPasswordPlugin from "../../plugins/adminforth-email-password-reset/index.js";
12+
import { v1 as uuid } from "uuid";
13+
import EmailAdapterAwsSes from "../../adapters/adminforth-email-adapter-aws-ses/index.js";
14+
15+
import OAuthPlugin from "../../plugins/adminforth-oauth";
16+
import AdminForthAdapterGoogleOauth2 from "../../adapters/adminforth-google-oauth-adapter";
17+
import AdminForthAdapterGithubOauth2 from "../../adapters/adminforth-github-oauth-adapter";
18+
import ListInPlaceEditPlugin from "../../plugins/adminforth-list-in-place-edit";
19+
20+
export default {
21+
dataSource: "maindb",
22+
table: "users",
23+
resourceId: "user_sub",
24+
label: "User Sub",
25+
26+
recordLabel: (r: any) => `👤 ${r.email}`,
27+
plugins: [
28+
new ListInPlaceEditPlugin({
29+
columns: ["role"]
30+
})
31+
],
32+
options: {
33+
allowedActions: {
34+
create: async ({
35+
adminUser,
36+
meta,
37+
}: {
38+
adminUser: AdminUser;
39+
meta: any;
40+
}) => {
41+
// console.log('create', adminUser, meta);
42+
return true;
43+
},
44+
delete: true,
45+
},
46+
},
47+
columns: [
48+
{
49+
name: "id",
50+
primaryKey: true,
51+
fillOnCreate: ({ initialRecord, adminUser }: any) => uuid(),
52+
showIn: ["list", "filter", "show"], // the default is full set
53+
},
54+
{
55+
name: "secret2fa",
56+
type: AdminForthDataTypes.STRING,
57+
showIn: [],
58+
backendOnly: true,
59+
},
60+
{
61+
name: "email",
62+
isUnique: true,
63+
required: true,
64+
enforceLowerCase: true,
65+
type: AdminForthDataTypes.STRING,
66+
validation: [AdminForth.Utils.EMAIL_VALIDATOR],
67+
},
68+
{
69+
name: "created_at",
70+
type: AdminForthDataTypes.DATETIME,
71+
showIn: ["list", "filter", "show"],
72+
fillOnCreate: ({ initialRecord, adminUser }: any) =>
73+
new Date().toISOString(),
74+
},
75+
{
76+
name: "password_hash",
77+
showIn: [],
78+
backendOnly: true, // will never go to frontend
79+
},
80+
{
81+
name: 'email_confirmed',
82+
type: AdminForthDataTypes.BOOLEAN,
83+
showIn: {
84+
list: true,
85+
show: true,
86+
edit: false,
87+
create: false
88+
}
89+
},
90+
{
91+
name: "role",
92+
enum: [
93+
{ value: 'superadmin', label: 'Super Admin' },
94+
{ value: "user", label: "User" },
95+
],
96+
},
97+
{
98+
name: "password",
99+
virtual: true, // field will not be persisted into db
100+
required: { create: true }, // to show only in create page
101+
editingNote: { edit: "Leave empty to keep password unchanged" },
102+
103+
minLength: 8,
104+
validation: [AdminForth.Utils.PASSWORD_VALIDATORS.UP_LOW_NUM],
105+
type: AdminForthDataTypes.STRING,
106+
showIn: ["create", "edit"], // to show in create and edit pages
107+
masked: true, // to show stars in input field
108+
},
109+
{
110+
name: "last_login_ip",
111+
showIn: ["show", "list", "filter"],
112+
},
113+
{
114+
name: "parentUserId",
115+
foreignResource: {
116+
resourceId: "users",
117+
}
118+
},
119+
// {
120+
// name: "email_confirmed",
121+
// },
122+
],
123+
hooks: {
124+
create: {
125+
beforeSave: async ({ record, adminUser, resource }: any) => {
126+
record.password_hash = await AdminForth.Utils.generatePasswordHash(
127+
record.password
128+
);
129+
return { ok: true, error: "" };
130+
// if return 'error': , record will not be saved and error will be proxied
131+
},
132+
},
133+
edit: {
134+
beforeSave: async ({ record, adminUser, resource }: any) => {
135+
if (record.password) {
136+
record.password_hash = await AdminForth.Utils.generatePasswordHash(
137+
record.password
138+
);
139+
}
140+
return { ok: true, error: "" };
141+
},
142+
// beforeDatasourceRequest: async ({ query, adminUser, resource }) => {
143+
// return { ok: true, error: false }
144+
// },
145+
// afterDatasourceResponse: async ({ response, adminUser }) => {
146+
// return { ok: true, error: false }
147+
// }
148+
},
149+
// list: {
150+
// beforeDatasourceRequest: async ({ query, adminUser }) => {
151+
// return { ok: true, error: false }
152+
// },
153+
// afterDatasourceResponse: async ({ response, adminUser }) => {
154+
// return { ok: true, error: false }
155+
// }
156+
// },
157+
// show: {
158+
// beforeDatasourceRequest: async ({ query, adminUser, resource }) => {
159+
// return { ok: true, error: false }
160+
// },
161+
// afterDatasourceResponse: async ({ response, adminUser, resource }) => {
162+
// return { ok: true, error: false }
163+
// }
164+
// },
165+
},
166+
} as AdminForthResourceInput;

dev-demo/resources/users.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import EmailAdapterAwsSes from "../../adapters/adminforth-email-adapter-aws-ses/
1515
import OAuthPlugin from "../../plugins/adminforth-oauth";
1616
import AdminForthAdapterGoogleOauth2 from "../../adapters/adminforth-google-oauth-adapter";
1717
import AdminForthAdapterGithubOauth2 from "../../adapters/adminforth-github-oauth-adapter";
18+
import ListInPlaceEditPlugin from "../../plugins/adminforth-list-in-place-edit";
1819

1920
export default {
2021
dataSource: "maindb",
@@ -38,7 +39,7 @@ export default {
3839
foreignResourceId: "audit_log",
3940
}),
4041
new ForeignInlineListPlugin({
41-
foreignResourceId: "users",
42+
foreignResourceId: "user_sub",
4243
}),
4344
new TwoFactorsAuthPlugin({
4445
twoFaSecretFieldName: "secret2fa",
@@ -103,6 +104,9 @@ export default {
103104
emailField: 'email',
104105
emailConfirmedField: 'email_confirmed'
105106
}),
107+
// new ListInPlaceEditPlugin({
108+
// columns: ["role"]
109+
// })
106110
],
107111
options: {
108112
allowedActions: {
@@ -165,7 +169,7 @@ export default {
165169
{
166170
name: "role",
167171
enum: [
168-
// { value: 'superadmin', label: 'Super Admin' },
172+
{ value: 'superadmin', label: 'Super Admin' },
169173
{ value: "user", label: "User" },
170174
],
171175
},
@@ -190,7 +194,7 @@ export default {
190194
foreignResource: {
191195
resourceId: "users",
192196
}
193-
}
197+
},
194198
// {
195199
// name: "email_confirmed",
196200
// },

live-demo/app/db.sqlite

160 KB
Binary file not shown.

0 commit comments

Comments
 (0)