Skip to content

Commit 3a02c71

Browse files
committed
chore: update dev demo
1 parent 8e62073 commit 3a02c71

File tree

7 files changed

+169
-29
lines changed

7 files changed

+169
-29
lines changed

dev-demo/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ export const admin = new AdminForth({
8686
return "Please use <b>adminforth</b> as username and <b>adminforth</b> as password"
8787
}
8888
},
89+
90+
avatarUrl: async (adminUser)=>{
91+
const plugin = admin.getPluginsByClassName('UploadPlugin').find(p => p.pluginOptions.pathColumnName === 'avatar') as any;
92+
if (!plugin) {
93+
throw new Error('Upload plugin for avatar not found');
94+
}
95+
if (adminUser.dbUser.avatar === null || adminUser.dbUser.avatar === undefined || adminUser.dbUser.avatar === '') {
96+
return '';
97+
}
98+
const imageUrl = await plugin.getFileDownloadUrl(adminUser.dbUser.avatar || '', 3600);
99+
return imageUrl;
100+
},
89101

90102
rememberMeDays: 30,
91103
beforeLoginConfirmation: [async ({adminUser, adminforth, extra}) => {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Warnings:
3+
4+
- Added the required column `is_active` to the `users` table without a default value. This is not possible if the table is not empty.
5+
6+
*/
7+
-- RedefineTables
8+
PRAGMA defer_foreign_keys=ON;
9+
PRAGMA foreign_keys=OFF;
10+
CREATE TABLE "new_users" (
11+
"id" TEXT NOT NULL PRIMARY KEY,
12+
"created_at" DATETIME NOT NULL,
13+
"email" TEXT NOT NULL,
14+
"role" TEXT NOT NULL,
15+
"password_hash" TEXT NOT NULL,
16+
"secret2fa" TEXT,
17+
"last_login_ip" TEXT,
18+
"email_confirmed" BOOLEAN DEFAULT false,
19+
"parentUserId" TEXT,
20+
"email_verified" BOOLEAN DEFAULT false,
21+
"is_active" BOOLEAN NOT NULL
22+
);
23+
INSERT INTO "new_users" ("created_at", "email", "email_confirmed", "email_verified", "id", "last_login_ip", "parentUserId", "password_hash", "role", "secret2fa") SELECT "created_at", "email", "email_confirmed", "email_verified", "id", "last_login_ip", "parentUserId", "password_hash", "role", "secret2fa" FROM "users";
24+
DROP TABLE "users";
25+
ALTER TABLE "new_users" RENAME TO "users";
26+
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
27+
CREATE INDEX "users_is_active_idx" ON "users"("is_active");
28+
PRAGMA foreign_keys=ON;
29+
PRAGMA defer_foreign_keys=OFF;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "users" ADD COLUMN "avatar" TEXT;

dev-demo/resources/apartments.ts

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -334,29 +334,6 @@ export default {
334334
plugins: [
335335
...(process.env.AWS_ACCESS_KEY_ID
336336
? [
337-
new BulkAiFlowPlugin({
338-
// askConfirmationBeforeGenerating: true,
339-
actionName: 'Analyze',
340-
attachFiles: async ({ record }: { record: any }) => {
341-
if (!record.apartment_image) {
342-
return [];
343-
}
344-
return [`https://tmpbucket-adminforth.s3.eu-central-1.amazonaws.com/${record.apartment_image}`];
345-
},
346-
visionAdapter: new AdminForthImageVisionAdapterOpenAi(
347-
{
348-
openAiApiKey: process.env.OPENAI_API_KEY as string,
349-
model: 'gpt-4.1-mini',
350-
}
351-
),
352-
fillFieldsFromImages: {
353-
'description': 'describe what is in the image, also take into account that price is {{price}}',
354-
'country': 'In which country it can be located?',
355-
'number_of_rooms': 'How many rooms are in the apartment? Just try to guess what is a typical one. If you do not know, just guess',
356-
'square_meter': 'Try to guess what is the typical square of the apartment in square meters? If you do not know, just guess',
357-
'listed': 'Is the apartment should be listed for sale? If you do not know, just guess, return boolean value',
358-
},
359-
}),
360337
new UploadPlugin({
361338
pathColumnName: "apartment_image",
362339

@@ -413,13 +390,13 @@ export default {
413390
new UploadPlugin({
414391
pathColumnName: "apartment_source",
415392

416-
storageAdapter: (sourcesAdapter = new AdminForthAdapterS3Storage({
393+
storageAdapter: new AdminForthAdapterS3Storage({
417394
region: "eu-central-1",
418395
bucket: "tmpbucket-adminforth",
419396
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
420397
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
421398
s3ACL: 'public-read', // ACL which will be set to uploaded file
422-
}), sourcesAdapter),
399+
}),
423400

424401
// storageAdapter: (sourcesAdapter = new AdminForthStorageAdapterLocalFilesystem({
425402
// fileSystemFolder: "./db/uploads", // folder where files will be stored on disk
@@ -445,10 +422,58 @@ export default {
445422
},
446423
preview: {
447424
// Used to display preview (if it is image) in list and show views
448-
// previewUrl: ({s3Path}) => `https://tmpbucket-adminforth.s3.eu-central-1.amazonaws.com/${s3Path}`,
425+
//previewUrl: ({filePath}) => `https://tmpbucket-adminforth.s3.eu-central-1.amazonaws.com/${filePath}`,
449426
maxWidth: "200px",
450427
},
451428
}),
429+
new BulkAiFlowPlugin({
430+
askConfirmationBeforeGenerating: true,
431+
actionName: 'Analyze',
432+
// attachFiles: async ({ record }: { record: any }) => {
433+
// if (!record.apartment_image) {
434+
// return [];
435+
// }
436+
// return [`https://tmpbucket-adminforth.s3.eu-central-1.amazonaws.com/${record.apartment_image}`];
437+
// },
438+
visionAdapter: new AdminForthImageVisionAdapterOpenAi(
439+
{
440+
openAiApiKey: process.env.OPENAI_API_KEY as string,
441+
model: 'gpt-4.1-mini',
442+
}
443+
),
444+
imageGenerationAdapter: new ImageGenerationAdapterOpenAI({
445+
openAiApiKey: process.env.OPENAI_API_KEY as string,
446+
model: 'gpt-image-1',
447+
}),
448+
textCompleteAdapter: new CompletionAdapterOpenAIChatGPT({
449+
openAiApiKey: process.env.OPENAI_API_KEY as string,
450+
model: 'gpt-4o',
451+
expert: {
452+
temperature: 0.7
453+
}
454+
}),
455+
fillPlainFields: {
456+
'description': 'Provide1234 a detailed and engaging description of the apartment based on its features and location. Highlight its unique selling points and amenities to attract potential buyers.',
457+
'listed': 'Based on the apartment features and market trends, should this apartment be listed for sale? Provide a yes or no answer.',
458+
'title': 'Create a catchy and appealing title for the apartment listing that highlights its best features and location.',
459+
},
460+
461+
// fillFieldsFromImages: {
462+
// 'description': 'describe what is in the image, also take into account that price is {{price}}',
463+
// 'country': 'In which country it can be located?',
464+
// 'number_of_rooms': 'How many rooms are in the apartment? Just try to guess what is a typical one. If you do not know, just guess',
465+
// 'square_meter': 'Try to guess what is the typical square of the apartment in square meters? If you do not know, just guess',
466+
// 'listed': 'Is the apartment should be listed for sale? If you do not know, just guess, return boolean value',
467+
// },
468+
generateImages: {
469+
apartment_source: {
470+
prompt: 'Transform this photo into a cartoon-style avatar. Maintain the person\'s features but apply cartoon styling. Do not add text or logos.',
471+
outputSize: '1024x1024',
472+
countToGenerate: 2,
473+
rateLimit: '3/1h'
474+
},
475+
},
476+
}),
452477
]
453478
: []),
454479
new ImportExportPlugin({}),

dev-demo/resources/description_image.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default {
5858
maxFileSize: 1024 * 1024 * 20, // 5MB
5959

6060

61-
s3Path: ({ originalFilename, originalExtension, contentType }) =>
61+
filePath: ({ originalFilename, originalExtension, contentType }) =>
6262
`description_images/${new Date().getFullYear()}/${uuid()}/${originalFilename}.${originalExtension}`,
6363

6464
preview: {

dev-demo/resources/users.ts

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import AdminForthAdapterKeycloakOauth2 from "../../adapters/adminforth-keycloak-
2020
import AdminForthAdapterMicrosoftOauth2 from "../../adapters/adminforth-microsoft-oauth-adapter";
2121
// import AdminForthAdapterTwitchOauth2 from "../../adapters/adminforth-twitch-oauth-adapter";
2222
import { randomUUID } from "crypto";
23+
import UserSoftDelete from "../../plugins/adminforth-user-soft-delete";
24+
import UploadPlugin from "../../plugins/adminforth-upload";
25+
import AdminForthAdapterS3Storage from "../../adapters/adminforth-storage-adapter-amazon-s3/index.js";
26+
import { createHook } from "async_hooks";
2327

2428
declare global {
2529
namespace NodeJS {
@@ -117,6 +121,35 @@ export default {
117121
},
118122
}
119123
}),
124+
new UploadPlugin({
125+
pathColumnName: "avatar",
126+
127+
storageAdapter: new AdminForthAdapterS3Storage({
128+
region: "eu-central-1",
129+
bucket: "tmpbucket-adminforth",
130+
accessKeyId: process.env.AWS_ACCESS_KEY_ID as string,
131+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
132+
// s3ACL: 'public-read', // ACL which will be set to uploaded file
133+
}),
134+
allowedFileExtensions: [
135+
"jpg",
136+
"jpeg",
137+
"png",
138+
"gif",
139+
"webm",
140+
"exe",
141+
"webp",
142+
],
143+
maxFileSize: 1024 * 1024 * 20, // 5MB
144+
// s3ACL: 'public-read', // ACL which will be set to uploaded file
145+
filePath: ({ originalFilename, originalExtension, contentType, record }) => {
146+
console.log("🔥", JSON.stringify(record));
147+
return `aparts/${new Date().getFullYear()}/${originalFilename}.${originalExtension}`
148+
},
149+
preview: {
150+
maxWidth: "200px",
151+
},
152+
}),
120153
...(process.env.AWS_ACCESS_KEY_ID
121154
? [
122155
new EmailResetPasswordPlugin({
@@ -151,6 +184,7 @@ export default {
151184
// },
152185
}),
153186
new OAuthPlugin({
187+
userAvatarField: "avatar",
154188
adapters: [
155189
new AdminForthAdapterGithubOauth2({
156190
clientID: process.env.GITHUB_CLIENT_ID,
@@ -159,6 +193,7 @@ export default {
159193
new AdminForthAdapterGoogleOauth2({
160194
clientID: process.env.GOOGLE_CLIENT_ID,
161195
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
196+
useOpenIdConnect: false,
162197
}),
163198
new AdminForthAdapterFacebookOauth2({
164199
clientID: process.env.FACEBOOK_CLIENT_ID,
@@ -167,7 +202,7 @@ export default {
167202
new AdminForthAdapterMicrosoftOauth2({
168203
clientID: process.env.MICROSOFT_CLIENT_ID,
169204
clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
170-
useOpenIdConnect: true,
205+
useOpenIdConnect: false,
171206
}),
172207
// new AdminForthAdapterTwitchOauth2({
173208
// clientID: process.env.TWITCH_CLIENT_ID,
@@ -184,6 +219,16 @@ export default {
184219
emailField: 'email',
185220
emailConfirmedField: 'email_confirmed'
186221
}),
222+
new UserSoftDelete({
223+
activeFieldName: "is_active",
224+
//in canDeactivate we pass a function, that specify adminusers roles, which can seactivate other adminusers
225+
canDeactivate: async (adminUser: AdminUser) => {
226+
if (adminUser.dbUser.role === "superadmin") {
227+
return true;
228+
}
229+
return false;
230+
}
231+
}),
187232
],
188233
options: {
189234
actions: [
@@ -234,6 +279,9 @@ export default {
234279
enforceLowerCase: true,
235280
type: AdminForthDataTypes.STRING,
236281
validation: [AdminForth.Utils.EMAIL_VALIDATOR],
282+
foreignResource: {
283+
resourceId: "audit_log",
284+
}
237285
},
238286
{
239287
name: "created_at",
@@ -285,7 +333,28 @@ export default {
285333
foreignResource: {
286334
resourceId: "users",
287335
}
288-
}
336+
},
337+
{
338+
name: "is_active",
339+
type: AdminForthDataTypes.BOOLEAN,
340+
label: "Is Active",
341+
fillOnCreate: () => true,
342+
filterOptions: {
343+
multiselect: false,
344+
},
345+
showIn: {
346+
list: true,
347+
filter: true,
348+
show: true,
349+
create: false,
350+
edit: true,
351+
},
352+
},
353+
{
354+
name: "avatar",
355+
type: AdminForthDataTypes.STRING,
356+
showIn: ["show", "edit", "create" ],
357+
},
289358
// {
290359
// name: "email_confirmed",
291360
// },

dev-demo/schema.prisma

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ model users {
1818
email_confirmed Boolean? @default(false)
1919
parentUserId String?
2020
email_verified Boolean? @default(false)
21+
is_active Boolean
22+
@@index([is_active])
23+
avatar String?
2124
}
2225

2326
model apartments {

0 commit comments

Comments
 (0)