gavaengine 0.1.0 → 1.2.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/auth/index.d.ts +42 -0
- package/dist/auth/index.js +12 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/{chunk-KCQJHXZP.js → chunk-ICIFEKSX.js} +2 -2
- package/dist/chunk-IK24OCFW.js +534 -0
- package/dist/chunk-IK24OCFW.js.map +1 -0
- package/dist/{chunk-CE7E5MAB.js → chunk-KQHQOMGL.js} +6 -7
- package/dist/{chunk-CE7E5MAB.js.map → chunk-KQHQOMGL.js.map} +1 -1
- package/dist/chunk-QO42DDRU.js +113 -0
- package/dist/chunk-QO42DDRU.js.map +1 -0
- package/dist/cli/index.js +0 -1
- package/dist/components/index.js +2 -2
- package/dist/handlers/index.d.ts +33 -3
- package/dist/handlers/index.js +385 -128
- package/dist/handlers/index.js.map +1 -1
- package/dist/i18n/index.d.ts +114 -0
- package/dist/i18n/index.js +249 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/{index-CIX0MBHm.d.ts → index-Ng6yRSAA.d.ts} +117 -2
- package/dist/index.d.ts +19 -5
- package/dist/index.js +69 -39
- package/dist/index.js.map +1 -1
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +2 -2
- package/dist/types-d8-k_4dN.d.ts +19 -0
- package/package.json +12 -1
- package/dist/chunk-GGD7I4JO.js +0 -253
- package/dist/chunk-GGD7I4JO.js.map +0 -1
- /package/dist/{chunk-KCQJHXZP.js.map → chunk-ICIFEKSX.js.map} +0 -0
package/dist/handlers/index.js
CHANGED
|
@@ -1,8 +1,320 @@
|
|
|
1
|
+
// src/i18n/it.ts
|
|
2
|
+
var it = {
|
|
3
|
+
content: {
|
|
4
|
+
articles: "Articoli",
|
|
5
|
+
newArticle: "Nuovo articolo",
|
|
6
|
+
titlePlaceholder: "Titolo dell'articolo",
|
|
7
|
+
excerptPlaceholder: "Breve descrizione dell'articolo...",
|
|
8
|
+
slugPlaceholder: "slug-articolo",
|
|
9
|
+
authorPlaceholder: "Nome dell'autore",
|
|
10
|
+
category: "Categoria",
|
|
11
|
+
selectCategory: "Seleziona categoria",
|
|
12
|
+
excerpt: "Estratto",
|
|
13
|
+
author: "Autore",
|
|
14
|
+
slugUrl: "Slug URL",
|
|
15
|
+
noArticles: "Nessun articolo.",
|
|
16
|
+
noArticlesSearch: "Nessun articolo trovato.",
|
|
17
|
+
searchArticles: "Cerca articoli...",
|
|
18
|
+
coverImageLabel: "Immagine di copertina",
|
|
19
|
+
coverImageHint: "Scegli dalla libreria o carica un nuovo file",
|
|
20
|
+
viewArticle: "Vedi articolo pubblicato",
|
|
21
|
+
untitled: "Senza titolo"
|
|
22
|
+
},
|
|
23
|
+
editor: {
|
|
24
|
+
publish: "Pubblica",
|
|
25
|
+
unpublish: "Ritira",
|
|
26
|
+
saveDraft: "Salva bozza",
|
|
27
|
+
revisions: "Cronologia",
|
|
28
|
+
saving: "Salvando...",
|
|
29
|
+
saved: "Salvato",
|
|
30
|
+
saveError: "Errore nel salvataggio",
|
|
31
|
+
noRevisions: "Nessuna revisione salvata.",
|
|
32
|
+
restore: "Ripristina",
|
|
33
|
+
restoreConfirm: "Ripristinare questa revisione? Lo stato attuale verr\xE0 salvato prima del ripristino.",
|
|
34
|
+
beforeRestore: "Prima del ripristino",
|
|
35
|
+
publishedNote: "Pubblicato",
|
|
36
|
+
preview: "Anteprima",
|
|
37
|
+
placeholder: "Inizia a scrivere il tuo articolo..."
|
|
38
|
+
},
|
|
39
|
+
media: {
|
|
40
|
+
media: "Media",
|
|
41
|
+
noMedia: "Nessun file caricato.",
|
|
42
|
+
noMediaSearch: "Nessun file trovato.",
|
|
43
|
+
chooseFile: "Scegli file",
|
|
44
|
+
dragHint: "Trascina un'immagine qui oppure",
|
|
45
|
+
uploadHint: "JPEG, PNG, WebP, GIF (max 5MB)",
|
|
46
|
+
mediaLibrary: "Libreria media",
|
|
47
|
+
uploadNew: "Carica nuovo",
|
|
48
|
+
searchFiles: "Cerca file...",
|
|
49
|
+
selectImage: "Seleziona immagine",
|
|
50
|
+
noImages: "Nessuna immagine nella libreria.",
|
|
51
|
+
noImagesSearch: "Nessuna immagine trovata.",
|
|
52
|
+
copyUrl: "Copia URL",
|
|
53
|
+
editImage: "Modifica immagine",
|
|
54
|
+
restoreOriginal: "Ripristina originale",
|
|
55
|
+
freeAspect: "Libero"
|
|
56
|
+
},
|
|
57
|
+
users: {
|
|
58
|
+
users: "Utenti",
|
|
59
|
+
name: "Nome",
|
|
60
|
+
email: "Email",
|
|
61
|
+
password: "Password",
|
|
62
|
+
passwordEditHint: " (lascia vuoto per non modificarla)",
|
|
63
|
+
role: "Ruolo",
|
|
64
|
+
createdAt: "Creato il",
|
|
65
|
+
actions: "Azioni",
|
|
66
|
+
createUser: "Crea utente",
|
|
67
|
+
unauthorized: "Non autorizzato",
|
|
68
|
+
notAuthenticated: "Non autenticato",
|
|
69
|
+
allFieldsRequired: "Tutti i campi sono obbligatori.",
|
|
70
|
+
passwordMinLength: "La password deve avere almeno 6 caratteri.",
|
|
71
|
+
emailExists: "Esiste gi\xE0 un utente con questa email.",
|
|
72
|
+
invalidRole: "Ruolo non valido.",
|
|
73
|
+
cannotDeleteSelf: "Non puoi eliminare il tuo stesso account."
|
|
74
|
+
},
|
|
75
|
+
common: {
|
|
76
|
+
statistics: "Statistiche",
|
|
77
|
+
settings: "Impostazioni",
|
|
78
|
+
delete: "Elimina",
|
|
79
|
+
edit: "Modifica",
|
|
80
|
+
search: "Cerca",
|
|
81
|
+
draft: "Bozza",
|
|
82
|
+
published: "Pubblicato",
|
|
83
|
+
all: "Tutti",
|
|
84
|
+
drafts: "Bozze",
|
|
85
|
+
loading: "Caricamento...",
|
|
86
|
+
confirm: "Conferma",
|
|
87
|
+
cancel: "Annulla",
|
|
88
|
+
apply: "Applica",
|
|
89
|
+
change: "Cambia",
|
|
90
|
+
logout: "Esci",
|
|
91
|
+
saveChanges: "Salva modifiche",
|
|
92
|
+
updated: "Aggiornato",
|
|
93
|
+
status: "Stato",
|
|
94
|
+
title: "Titolo",
|
|
95
|
+
deleteConfirm: (title) => `Eliminare "${title || "Senza titolo"}"?`,
|
|
96
|
+
unpublishConfirm: (title) => `Ritirare "${title || "Senza titolo"}"? L'articolo torner\xE0 in bozza.`,
|
|
97
|
+
deleteUserConfirm: (name) => `Sei sicuro di voler eliminare l'utente "${name}"?`,
|
|
98
|
+
totalArticles: (count) => `${count} articol${count === 1 ? "o" : "i"} totali`,
|
|
99
|
+
totalFiles: (count) => `${count} file caricati`
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/i18n/en.ts
|
|
104
|
+
var en = {
|
|
105
|
+
content: {
|
|
106
|
+
articles: "Articles",
|
|
107
|
+
newArticle: "New article",
|
|
108
|
+
titlePlaceholder: "Article title",
|
|
109
|
+
excerptPlaceholder: "Brief description of the article...",
|
|
110
|
+
slugPlaceholder: "article-slug",
|
|
111
|
+
authorPlaceholder: "Author name",
|
|
112
|
+
category: "Category",
|
|
113
|
+
selectCategory: "Select category",
|
|
114
|
+
excerpt: "Excerpt",
|
|
115
|
+
author: "Author",
|
|
116
|
+
slugUrl: "URL Slug",
|
|
117
|
+
noArticles: "No articles.",
|
|
118
|
+
noArticlesSearch: "No articles found.",
|
|
119
|
+
searchArticles: "Search articles...",
|
|
120
|
+
coverImageLabel: "Cover image",
|
|
121
|
+
coverImageHint: "Choose from library or upload a new file",
|
|
122
|
+
viewArticle: "View published article",
|
|
123
|
+
untitled: "Untitled"
|
|
124
|
+
},
|
|
125
|
+
editor: {
|
|
126
|
+
publish: "Publish",
|
|
127
|
+
unpublish: "Unpublish",
|
|
128
|
+
saveDraft: "Save draft",
|
|
129
|
+
revisions: "History",
|
|
130
|
+
saving: "Saving...",
|
|
131
|
+
saved: "Saved",
|
|
132
|
+
saveError: "Error saving",
|
|
133
|
+
noRevisions: "No revisions saved.",
|
|
134
|
+
restore: "Restore",
|
|
135
|
+
restoreConfirm: "Restore this revision? The current state will be saved before restoring.",
|
|
136
|
+
beforeRestore: "Before restore",
|
|
137
|
+
publishedNote: "Published",
|
|
138
|
+
preview: "Preview",
|
|
139
|
+
placeholder: "Start writing your article..."
|
|
140
|
+
},
|
|
141
|
+
media: {
|
|
142
|
+
media: "Media",
|
|
143
|
+
noMedia: "No files uploaded.",
|
|
144
|
+
noMediaSearch: "No files found.",
|
|
145
|
+
chooseFile: "Choose file",
|
|
146
|
+
dragHint: "Drag an image here or",
|
|
147
|
+
uploadHint: "JPEG, PNG, WebP, GIF (max 5MB)",
|
|
148
|
+
mediaLibrary: "Media library",
|
|
149
|
+
uploadNew: "Upload new",
|
|
150
|
+
searchFiles: "Search files...",
|
|
151
|
+
selectImage: "Select image",
|
|
152
|
+
noImages: "No images in library.",
|
|
153
|
+
noImagesSearch: "No images found.",
|
|
154
|
+
copyUrl: "Copy URL",
|
|
155
|
+
editImage: "Edit image",
|
|
156
|
+
restoreOriginal: "Restore original",
|
|
157
|
+
freeAspect: "Free"
|
|
158
|
+
},
|
|
159
|
+
users: {
|
|
160
|
+
users: "Users",
|
|
161
|
+
name: "Name",
|
|
162
|
+
email: "Email",
|
|
163
|
+
password: "Password",
|
|
164
|
+
passwordEditHint: " (leave blank to keep current)",
|
|
165
|
+
role: "Role",
|
|
166
|
+
createdAt: "Created at",
|
|
167
|
+
actions: "Actions",
|
|
168
|
+
createUser: "Create user",
|
|
169
|
+
unauthorized: "Unauthorized",
|
|
170
|
+
notAuthenticated: "Not authenticated",
|
|
171
|
+
allFieldsRequired: "All fields are required.",
|
|
172
|
+
passwordMinLength: "Password must be at least 6 characters.",
|
|
173
|
+
emailExists: "A user with this email already exists.",
|
|
174
|
+
invalidRole: "Invalid role.",
|
|
175
|
+
cannotDeleteSelf: "You cannot delete your own account."
|
|
176
|
+
},
|
|
177
|
+
common: {
|
|
178
|
+
statistics: "Statistics",
|
|
179
|
+
settings: "Settings",
|
|
180
|
+
delete: "Delete",
|
|
181
|
+
edit: "Edit",
|
|
182
|
+
search: "Search",
|
|
183
|
+
draft: "Draft",
|
|
184
|
+
published: "Published",
|
|
185
|
+
all: "All",
|
|
186
|
+
drafts: "Drafts",
|
|
187
|
+
loading: "Loading...",
|
|
188
|
+
confirm: "Confirm",
|
|
189
|
+
cancel: "Cancel",
|
|
190
|
+
apply: "Apply",
|
|
191
|
+
change: "Change",
|
|
192
|
+
logout: "Logout",
|
|
193
|
+
saveChanges: "Save changes",
|
|
194
|
+
updated: "Updated",
|
|
195
|
+
status: "Status",
|
|
196
|
+
title: "Title",
|
|
197
|
+
deleteConfirm: (title) => `Delete "${title || "Untitled"}"?`,
|
|
198
|
+
unpublishConfirm: (title) => `Unpublish "${title || "Untitled"}"? The article will go back to draft.`,
|
|
199
|
+
deleteUserConfirm: (name) => `Are you sure you want to delete user "${name}"?`,
|
|
200
|
+
totalArticles: (count) => `${count} total article${count === 1 ? "" : "s"}`,
|
|
201
|
+
totalFiles: (count) => `${count} uploaded file${count === 1 ? "" : "s"}`
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// src/i18n/index.ts
|
|
206
|
+
var builtinLocales = { it, en };
|
|
207
|
+
function loadLocale(locale) {
|
|
208
|
+
const found = builtinLocales[locale];
|
|
209
|
+
if (!found) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`Locale "${locale}" not found. Available: ${Object.keys(builtinLocales).join(", ")}`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return found;
|
|
215
|
+
}
|
|
216
|
+
|
|
1
217
|
// src/config.ts
|
|
218
|
+
function localeToStrings(locale) {
|
|
219
|
+
return {
|
|
220
|
+
// content
|
|
221
|
+
articles: locale.content.articles,
|
|
222
|
+
newArticle: locale.content.newArticle,
|
|
223
|
+
titlePlaceholder: locale.content.titlePlaceholder,
|
|
224
|
+
excerptPlaceholder: locale.content.excerptPlaceholder,
|
|
225
|
+
slugPlaceholder: locale.content.slugPlaceholder,
|
|
226
|
+
authorPlaceholder: locale.content.authorPlaceholder,
|
|
227
|
+
category: locale.content.category,
|
|
228
|
+
selectCategory: locale.content.selectCategory,
|
|
229
|
+
excerpt: locale.content.excerpt,
|
|
230
|
+
author: locale.content.author,
|
|
231
|
+
slugUrl: locale.content.slugUrl,
|
|
232
|
+
noArticles: locale.content.noArticles,
|
|
233
|
+
noArticlesSearch: locale.content.noArticlesSearch,
|
|
234
|
+
searchArticles: locale.content.searchArticles,
|
|
235
|
+
coverImageLabel: locale.content.coverImageLabel,
|
|
236
|
+
coverImageHint: locale.content.coverImageHint,
|
|
237
|
+
viewArticle: locale.content.viewArticle,
|
|
238
|
+
untitled: locale.content.untitled,
|
|
239
|
+
// editor
|
|
240
|
+
publish: locale.editor.publish,
|
|
241
|
+
unpublish: locale.editor.unpublish,
|
|
242
|
+
saveDraft: locale.editor.saveDraft,
|
|
243
|
+
revisions: locale.editor.revisions,
|
|
244
|
+
saving: locale.editor.saving,
|
|
245
|
+
saved: locale.editor.saved,
|
|
246
|
+
saveError: locale.editor.saveError,
|
|
247
|
+
noRevisions: locale.editor.noRevisions,
|
|
248
|
+
restore: locale.editor.restore,
|
|
249
|
+
restoreConfirm: locale.editor.restoreConfirm,
|
|
250
|
+
beforeRestore: locale.editor.beforeRestore,
|
|
251
|
+
publishedNote: locale.editor.publishedNote,
|
|
252
|
+
preview: locale.editor.preview,
|
|
253
|
+
// media
|
|
254
|
+
media: locale.media.media,
|
|
255
|
+
noMedia: locale.media.noMedia,
|
|
256
|
+
noMediaSearch: locale.media.noMediaSearch,
|
|
257
|
+
chooseFile: locale.media.chooseFile,
|
|
258
|
+
dragHint: locale.media.dragHint,
|
|
259
|
+
uploadHint: locale.media.uploadHint,
|
|
260
|
+
mediaLibrary: locale.media.mediaLibrary,
|
|
261
|
+
uploadNew: locale.media.uploadNew,
|
|
262
|
+
searchFiles: locale.media.searchFiles,
|
|
263
|
+
selectImage: locale.media.selectImage,
|
|
264
|
+
noImages: locale.media.noImages,
|
|
265
|
+
noImagesSearch: locale.media.noImagesSearch,
|
|
266
|
+
copyUrl: locale.media.copyUrl,
|
|
267
|
+
editImage: locale.media.editImage,
|
|
268
|
+
restoreOriginal: locale.media.restoreOriginal,
|
|
269
|
+
freeAspect: locale.media.freeAspect,
|
|
270
|
+
// users
|
|
271
|
+
users: locale.users.users,
|
|
272
|
+
name: locale.users.name,
|
|
273
|
+
email: locale.users.email,
|
|
274
|
+
password: locale.users.password,
|
|
275
|
+
passwordEditHint: locale.users.passwordEditHint,
|
|
276
|
+
role: locale.users.role,
|
|
277
|
+
createdAt: locale.users.createdAt,
|
|
278
|
+
actions: locale.users.actions,
|
|
279
|
+
createUser: locale.users.createUser,
|
|
280
|
+
unauthorized: locale.users.unauthorized,
|
|
281
|
+
notAuthenticated: locale.users.notAuthenticated,
|
|
282
|
+
allFieldsRequired: locale.users.allFieldsRequired,
|
|
283
|
+
passwordMinLength: locale.users.passwordMinLength,
|
|
284
|
+
emailExists: locale.users.emailExists,
|
|
285
|
+
invalidRole: locale.users.invalidRole,
|
|
286
|
+
cannotDeleteSelf: locale.users.cannotDeleteSelf,
|
|
287
|
+
// common
|
|
288
|
+
statistics: locale.common.statistics,
|
|
289
|
+
settings: locale.common.settings,
|
|
290
|
+
delete: locale.common.delete,
|
|
291
|
+
edit: locale.common.edit,
|
|
292
|
+
search: locale.common.search,
|
|
293
|
+
draft: locale.common.draft,
|
|
294
|
+
published: locale.common.published,
|
|
295
|
+
all: locale.common.all,
|
|
296
|
+
drafts: locale.common.drafts,
|
|
297
|
+
loading: locale.common.loading,
|
|
298
|
+
confirm: locale.common.confirm,
|
|
299
|
+
cancel: locale.common.cancel,
|
|
300
|
+
apply: locale.common.apply,
|
|
301
|
+
change: locale.common.change,
|
|
302
|
+
logout: locale.common.logout,
|
|
303
|
+
saveChanges: locale.common.saveChanges,
|
|
304
|
+
updated: locale.common.updated,
|
|
305
|
+
status: locale.common.status,
|
|
306
|
+
title: locale.common.title,
|
|
307
|
+
deleteConfirm: locale.common.deleteConfirm,
|
|
308
|
+
unpublishConfirm: locale.common.unpublishConfirm,
|
|
309
|
+
deleteUserConfirm: locale.common.deleteUserConfirm,
|
|
310
|
+
totalArticles: locale.common.totalArticles,
|
|
311
|
+
totalFiles: locale.common.totalFiles
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
var DEFAULT_STRINGS = localeToStrings(loadLocale("it"));
|
|
2
315
|
var DEFAULT_CONFIG = {
|
|
3
316
|
branding: {
|
|
4
|
-
name: "GavaEngine"
|
|
5
|
-
splashWords: ["Powerful", "Flexible", "Modular", "Secure", "Customizable"]
|
|
317
|
+
name: "GavaEngine"
|
|
6
318
|
},
|
|
7
319
|
roles: {
|
|
8
320
|
list: ["admin", "redattore", "scrittore", "lettore"],
|
|
@@ -16,6 +328,18 @@ var DEFAULT_CONFIG = {
|
|
|
16
328
|
canPublish: (role) => role === "admin" || role === "redattore",
|
|
17
329
|
adminRole: "admin"
|
|
18
330
|
},
|
|
331
|
+
statuses: {
|
|
332
|
+
draft: "bozza",
|
|
333
|
+
published: "pubblicato"
|
|
334
|
+
},
|
|
335
|
+
locale: "it",
|
|
336
|
+
models: {
|
|
337
|
+
article: "article",
|
|
338
|
+
articleRevision: "articleRevision",
|
|
339
|
+
articleView: "articleView",
|
|
340
|
+
media: "media",
|
|
341
|
+
user: "user"
|
|
342
|
+
},
|
|
19
343
|
categories: [
|
|
20
344
|
"Cultura ed Intercultura",
|
|
21
345
|
"Fatti ed Eventi",
|
|
@@ -50,95 +374,7 @@ var DEFAULT_CONFIG = {
|
|
|
50
374
|
login: "/login",
|
|
51
375
|
home: "/"
|
|
52
376
|
},
|
|
53
|
-
strings:
|
|
54
|
-
articles: "Articoli",
|
|
55
|
-
newArticle: "Nuovo articolo",
|
|
56
|
-
media: "Media",
|
|
57
|
-
users: "Utenti",
|
|
58
|
-
statistics: "Statistiche",
|
|
59
|
-
settings: "Impostazioni",
|
|
60
|
-
revisions: "Cronologia",
|
|
61
|
-
publish: "Pubblica",
|
|
62
|
-
unpublish: "Ritira",
|
|
63
|
-
saveDraft: "Salva bozza",
|
|
64
|
-
delete: "Elimina",
|
|
65
|
-
edit: "Modifica",
|
|
66
|
-
search: "Cerca",
|
|
67
|
-
titlePlaceholder: "Titolo dell'articolo",
|
|
68
|
-
excerptPlaceholder: "Breve descrizione dell'articolo...",
|
|
69
|
-
slugPlaceholder: "slug-articolo",
|
|
70
|
-
authorPlaceholder: "Nome dell'autore",
|
|
71
|
-
category: "Categoria",
|
|
72
|
-
selectCategory: "Seleziona categoria",
|
|
73
|
-
excerpt: "Estratto",
|
|
74
|
-
author: "Autore",
|
|
75
|
-
slugUrl: "Slug URL",
|
|
76
|
-
draft: "Bozza",
|
|
77
|
-
published: "Pubblicato",
|
|
78
|
-
all: "Tutti",
|
|
79
|
-
drafts: "Bozze",
|
|
80
|
-
saving: "Salvando...",
|
|
81
|
-
saved: "Salvato",
|
|
82
|
-
saveError: "Errore nel salvataggio",
|
|
83
|
-
noArticles: "Nessun articolo.",
|
|
84
|
-
noArticlesSearch: "Nessun articolo trovato.",
|
|
85
|
-
noMedia: "Nessun file caricato.",
|
|
86
|
-
noMediaSearch: "Nessun file trovato.",
|
|
87
|
-
noRevisions: "Nessuna revisione salvata.",
|
|
88
|
-
loading: "Caricamento...",
|
|
89
|
-
confirm: "Conferma",
|
|
90
|
-
cancel: "Annulla",
|
|
91
|
-
apply: "Applica",
|
|
92
|
-
change: "Cambia",
|
|
93
|
-
logout: "Esci",
|
|
94
|
-
viewArticle: "Vedi articolo pubblicato",
|
|
95
|
-
preview: "Anteprima",
|
|
96
|
-
restore: "Ripristina",
|
|
97
|
-
restoreConfirm: "Ripristinare questa revisione? Lo stato attuale verr\xE0 salvato prima del ripristino.",
|
|
98
|
-
beforeRestore: "Prima del ripristino",
|
|
99
|
-
publishedNote: "Pubblicato",
|
|
100
|
-
deleteConfirm: (title) => `Eliminare "${title || "Senza titolo"}"?`,
|
|
101
|
-
unpublishConfirm: (title) => `Ritirare "${title || "Senza titolo"}"? L'articolo torner\xE0 in bozza.`,
|
|
102
|
-
deleteUserConfirm: (name) => `Sei sicuro di voler eliminare l'utente "${name}"?`,
|
|
103
|
-
totalArticles: (count) => `${count} articol${count === 1 ? "o" : "i"} totali`,
|
|
104
|
-
totalFiles: (count) => `${count} file caricati`,
|
|
105
|
-
coverImageLabel: "Immagine di copertina",
|
|
106
|
-
coverImageHint: "Scegli dalla libreria o carica un nuovo file",
|
|
107
|
-
chooseFile: "Scegli file",
|
|
108
|
-
dragHint: "Trascina un'immagine qui oppure",
|
|
109
|
-
uploadHint: "JPEG, PNG, WebP, GIF (max 5MB)",
|
|
110
|
-
mediaLibrary: "Libreria media",
|
|
111
|
-
uploadNew: "Carica nuovo",
|
|
112
|
-
searchFiles: "Cerca file...",
|
|
113
|
-
searchArticles: "Cerca articoli...",
|
|
114
|
-
selectImage: "Seleziona immagine",
|
|
115
|
-
noImages: "Nessuna immagine nella libreria.",
|
|
116
|
-
noImagesSearch: "Nessuna immagine trovata.",
|
|
117
|
-
copyUrl: "Copia URL",
|
|
118
|
-
editImage: "Modifica immagine",
|
|
119
|
-
restoreOriginal: "Ripristina originale",
|
|
120
|
-
freeAspect: "Libero",
|
|
121
|
-
unauthorized: "Non autorizzato",
|
|
122
|
-
notAuthenticated: "Non autenticato",
|
|
123
|
-
allFieldsRequired: "Tutti i campi sono obbligatori.",
|
|
124
|
-
passwordMinLength: "La password deve avere almeno 6 caratteri.",
|
|
125
|
-
emailExists: "Esiste gi\xE0 un utente con questa email.",
|
|
126
|
-
invalidRole: "Ruolo non valido.",
|
|
127
|
-
cannotDeleteSelf: "Non puoi eliminare il tuo stesso account.",
|
|
128
|
-
name: "Nome",
|
|
129
|
-
email: "Email",
|
|
130
|
-
password: "Password",
|
|
131
|
-
passwordEditHint: " (lascia vuoto per non modificarla)",
|
|
132
|
-
role: "Ruolo",
|
|
133
|
-
createdAt: "Creato il",
|
|
134
|
-
actions: "Azioni",
|
|
135
|
-
createUser: "Crea utente",
|
|
136
|
-
saveChanges: "Salva modifiche",
|
|
137
|
-
updated: "Aggiornato",
|
|
138
|
-
status: "Stato",
|
|
139
|
-
title: "Titolo",
|
|
140
|
-
untitled: "Senza titolo"
|
|
141
|
-
}
|
|
377
|
+
strings: DEFAULT_STRINGS
|
|
142
378
|
};
|
|
143
379
|
function deepMerge(target, source) {
|
|
144
380
|
const result = { ...target };
|
|
@@ -157,32 +393,47 @@ function deepMerge(target, source) {
|
|
|
157
393
|
return result;
|
|
158
394
|
}
|
|
159
395
|
function defineConfig(overrides = {}) {
|
|
160
|
-
|
|
396
|
+
const locale = overrides.locale ?? DEFAULT_CONFIG.locale;
|
|
397
|
+
const baseStrings = localeToStrings(loadLocale(locale));
|
|
398
|
+
const configWithLocale = {
|
|
399
|
+
...DEFAULT_CONFIG,
|
|
400
|
+
strings: baseStrings
|
|
401
|
+
};
|
|
402
|
+
if (!overrides.editor?.placeholder) {
|
|
403
|
+
const localeData = loadLocale(locale);
|
|
404
|
+
configWithLocale.editor = {
|
|
405
|
+
...configWithLocale.editor,
|
|
406
|
+
placeholder: localeData.editor.placeholder
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
return deepMerge(configWithLocale, overrides);
|
|
161
410
|
}
|
|
162
411
|
|
|
163
412
|
// src/handlers/revisions.ts
|
|
164
413
|
function createRevisionHandlers(prisma, config) {
|
|
165
414
|
const throttleMs = config.editor.revisionThrottleMinutes * 60 * 1e3;
|
|
415
|
+
const articleModel = config.models.article;
|
|
416
|
+
const revisionModel = config.models.articleRevision;
|
|
166
417
|
return {
|
|
167
418
|
async getRevisions(articleId) {
|
|
168
|
-
return prisma.
|
|
419
|
+
return prisma[revisionModel].findMany({
|
|
169
420
|
where: { articleId },
|
|
170
421
|
include: { editor: { select: { name: true } } },
|
|
171
422
|
orderBy: { createdAt: "desc" }
|
|
172
423
|
});
|
|
173
424
|
},
|
|
174
425
|
async restoreRevision(articleId, revisionId, editorId) {
|
|
175
|
-
const article = await prisma.
|
|
426
|
+
const article = await prisma[articleModel].findUnique({
|
|
176
427
|
where: { id: articleId }
|
|
177
428
|
});
|
|
178
429
|
if (!article) throw new Error("Article not found");
|
|
179
|
-
const revision = await prisma.
|
|
430
|
+
const revision = await prisma[revisionModel].findUnique({
|
|
180
431
|
where: { id: revisionId }
|
|
181
432
|
});
|
|
182
433
|
if (!revision || revision.articleId !== articleId) {
|
|
183
434
|
throw new Error("Revision not found");
|
|
184
435
|
}
|
|
185
|
-
await prisma.
|
|
436
|
+
await prisma[revisionModel].create({
|
|
186
437
|
data: {
|
|
187
438
|
articleId,
|
|
188
439
|
title: article.title,
|
|
@@ -194,7 +445,7 @@ function createRevisionHandlers(prisma, config) {
|
|
|
194
445
|
note: config.strings.beforeRestore
|
|
195
446
|
}
|
|
196
447
|
});
|
|
197
|
-
await prisma.
|
|
448
|
+
await prisma[articleModel].update({
|
|
198
449
|
where: { id: articleId },
|
|
199
450
|
data: {
|
|
200
451
|
title: revision.title,
|
|
@@ -208,17 +459,17 @@ function createRevisionHandlers(prisma, config) {
|
|
|
208
459
|
return { success: true };
|
|
209
460
|
},
|
|
210
461
|
async createRevisionSnapshot(articleId, editorId, note = "") {
|
|
211
|
-
const article = await prisma.
|
|
462
|
+
const article = await prisma[articleModel].findUnique({
|
|
212
463
|
where: { id: articleId }
|
|
213
464
|
});
|
|
214
465
|
if (!article) return;
|
|
215
466
|
const threshold = new Date(Date.now() - throttleMs);
|
|
216
|
-
const recent = await prisma.
|
|
467
|
+
const recent = await prisma[revisionModel].findFirst({
|
|
217
468
|
where: { articleId, createdAt: { gte: threshold } },
|
|
218
469
|
orderBy: { createdAt: "desc" }
|
|
219
470
|
});
|
|
220
471
|
if (recent && !note) return;
|
|
221
|
-
await prisma.
|
|
472
|
+
await prisma[revisionModel].create({
|
|
222
473
|
data: {
|
|
223
474
|
articleId,
|
|
224
475
|
title: article.title,
|
|
@@ -237,19 +488,20 @@ function createRevisionHandlers(prisma, config) {
|
|
|
237
488
|
// src/handlers/articles.ts
|
|
238
489
|
function createArticleHandlers(prisma, config) {
|
|
239
490
|
const revisionHandlers = createRevisionHandlers(prisma, config);
|
|
491
|
+
const articleModel = config.models.article;
|
|
240
492
|
return {
|
|
241
493
|
async getArticles() {
|
|
242
|
-
return prisma.
|
|
494
|
+
return prisma[articleModel].findMany({
|
|
243
495
|
orderBy: { updatedAt: "desc" }
|
|
244
496
|
});
|
|
245
497
|
},
|
|
246
498
|
async getArticleById(id) {
|
|
247
|
-
return prisma.
|
|
499
|
+
return prisma[articleModel].findUnique({
|
|
248
500
|
where: { id }
|
|
249
501
|
});
|
|
250
502
|
},
|
|
251
503
|
async createArticle(authorName) {
|
|
252
|
-
const article = await prisma.
|
|
504
|
+
const article = await prisma[articleModel].create({
|
|
253
505
|
data: {
|
|
254
506
|
authorName
|
|
255
507
|
}
|
|
@@ -257,23 +509,23 @@ function createArticleHandlers(prisma, config) {
|
|
|
257
509
|
return article.id;
|
|
258
510
|
},
|
|
259
511
|
async updateArticle(userId, id, data) {
|
|
260
|
-
const article = await prisma.
|
|
512
|
+
const article = await prisma[articleModel].findUnique({ where: { id } });
|
|
261
513
|
if (!article) throw new Error("Article not found");
|
|
262
514
|
await revisionHandlers.createRevisionSnapshot(id, userId);
|
|
263
|
-
await prisma.
|
|
515
|
+
await prisma[articleModel].update({
|
|
264
516
|
where: { id },
|
|
265
517
|
data: { ...data, updatedAt: /* @__PURE__ */ new Date() }
|
|
266
518
|
});
|
|
267
519
|
return { success: true };
|
|
268
520
|
},
|
|
269
521
|
async deleteArticle(id) {
|
|
270
|
-
const article = await prisma.
|
|
522
|
+
const article = await prisma[articleModel].findUnique({ where: { id } });
|
|
271
523
|
if (!article) throw new Error("Article not found");
|
|
272
|
-
await prisma.
|
|
524
|
+
await prisma[articleModel].delete({ where: { id } });
|
|
273
525
|
return { success: true };
|
|
274
526
|
},
|
|
275
527
|
async publishArticle(userId, id) {
|
|
276
|
-
const article = await prisma.
|
|
528
|
+
const article = await prisma[articleModel].findUnique({ where: { id } });
|
|
277
529
|
if (!article) throw new Error("Article not found");
|
|
278
530
|
if (!article.title || !article.slug) {
|
|
279
531
|
throw new Error(
|
|
@@ -285,22 +537,22 @@ function createArticleHandlers(prisma, config) {
|
|
|
285
537
|
userId,
|
|
286
538
|
config.strings.publishedNote
|
|
287
539
|
);
|
|
288
|
-
await prisma.
|
|
540
|
+
await prisma[articleModel].update({
|
|
289
541
|
where: { id },
|
|
290
542
|
data: {
|
|
291
|
-
status:
|
|
543
|
+
status: config.statuses.published,
|
|
292
544
|
publishedAt: /* @__PURE__ */ new Date()
|
|
293
545
|
}
|
|
294
546
|
});
|
|
295
547
|
return { success: true };
|
|
296
548
|
},
|
|
297
549
|
async unpublishArticle(id) {
|
|
298
|
-
const article = await prisma.
|
|
550
|
+
const article = await prisma[articleModel].findUnique({ where: { id } });
|
|
299
551
|
if (!article) throw new Error("Article not found");
|
|
300
|
-
await prisma.
|
|
552
|
+
await prisma[articleModel].update({
|
|
301
553
|
where: { id },
|
|
302
554
|
data: {
|
|
303
|
-
status:
|
|
555
|
+
status: config.statuses.draft,
|
|
304
556
|
publishedAt: null
|
|
305
557
|
}
|
|
306
558
|
});
|
|
@@ -312,9 +564,10 @@ function createArticleHandlers(prisma, config) {
|
|
|
312
564
|
// src/handlers/users.ts
|
|
313
565
|
import bcrypt from "bcryptjs";
|
|
314
566
|
function createUserHandlers(prisma, config) {
|
|
567
|
+
const userModel = config.models.user;
|
|
315
568
|
return {
|
|
316
569
|
async getUsers() {
|
|
317
|
-
return prisma.
|
|
570
|
+
return prisma[userModel].findMany({
|
|
318
571
|
select: {
|
|
319
572
|
id: true,
|
|
320
573
|
name: true,
|
|
@@ -326,7 +579,7 @@ function createUserHandlers(prisma, config) {
|
|
|
326
579
|
});
|
|
327
580
|
},
|
|
328
581
|
async getUserById(id) {
|
|
329
|
-
return prisma.
|
|
582
|
+
return prisma[userModel].findUnique({
|
|
330
583
|
where: { id },
|
|
331
584
|
select: {
|
|
332
585
|
id: true,
|
|
@@ -350,12 +603,12 @@ function createUserHandlers(prisma, config) {
|
|
|
350
603
|
if (password.length < 6) {
|
|
351
604
|
return { error: config.strings.passwordMinLength };
|
|
352
605
|
}
|
|
353
|
-
const existing = await prisma.
|
|
606
|
+
const existing = await prisma[userModel].findUnique({ where: { email } });
|
|
354
607
|
if (existing) {
|
|
355
608
|
return { error: config.strings.emailExists };
|
|
356
609
|
}
|
|
357
610
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
358
|
-
await prisma.
|
|
611
|
+
await prisma[userModel].create({
|
|
359
612
|
data: {
|
|
360
613
|
name,
|
|
361
614
|
email,
|
|
@@ -376,7 +629,7 @@ function createUserHandlers(prisma, config) {
|
|
|
376
629
|
if (!config.roles.list.includes(role)) {
|
|
377
630
|
return { error: config.strings.invalidRole };
|
|
378
631
|
}
|
|
379
|
-
const existing = await prisma.
|
|
632
|
+
const existing = await prisma[userModel].findUnique({ where: { email } });
|
|
380
633
|
if (existing && existing.id !== id) {
|
|
381
634
|
return { error: config.strings.emailExists };
|
|
382
635
|
}
|
|
@@ -391,7 +644,7 @@ function createUserHandlers(prisma, config) {
|
|
|
391
644
|
}
|
|
392
645
|
data.password = await bcrypt.hash(password, 10);
|
|
393
646
|
}
|
|
394
|
-
await prisma.
|
|
647
|
+
await prisma[userModel].update({
|
|
395
648
|
where: { id },
|
|
396
649
|
data
|
|
397
650
|
});
|
|
@@ -401,29 +654,31 @@ function createUserHandlers(prisma, config) {
|
|
|
401
654
|
if (currentUserId === id) {
|
|
402
655
|
return { error: config.strings.cannotDeleteSelf };
|
|
403
656
|
}
|
|
404
|
-
await prisma.
|
|
657
|
+
await prisma[userModel].delete({ where: { id } });
|
|
405
658
|
return { success: true };
|
|
406
659
|
}
|
|
407
660
|
};
|
|
408
661
|
}
|
|
409
662
|
|
|
410
663
|
// src/handlers/media.ts
|
|
411
|
-
function createMediaHandlers(prisma,
|
|
664
|
+
function createMediaHandlers(prisma, config) {
|
|
665
|
+
const mediaModel = config.models.media;
|
|
666
|
+
const articleModel = config.models.article;
|
|
412
667
|
return {
|
|
413
668
|
async getMedia(search) {
|
|
414
|
-
return prisma.
|
|
669
|
+
return prisma[mediaModel].findMany({
|
|
415
670
|
where: search ? { filename: { contains: search } } : void 0,
|
|
416
671
|
include: { uploader: { select: { name: true } } },
|
|
417
672
|
orderBy: { createdAt: "desc" }
|
|
418
673
|
});
|
|
419
674
|
},
|
|
420
675
|
async deleteMedia(userId, userRole, id, deleteFileFromDisk) {
|
|
421
|
-
const media = await prisma.
|
|
676
|
+
const media = await prisma[mediaModel].findUnique({ where: { id } });
|
|
422
677
|
if (!media) throw new Error("File not found");
|
|
423
678
|
if (userRole === "scrittore" && media.uploaderId !== userId) {
|
|
424
679
|
throw new Error("Unauthorized");
|
|
425
680
|
}
|
|
426
|
-
const usedInArticles = await prisma.
|
|
681
|
+
const usedInArticles = await prisma[articleModel].findMany({
|
|
427
682
|
where: {
|
|
428
683
|
OR: [
|
|
429
684
|
{ coverImage: media.path },
|
|
@@ -444,7 +699,7 @@ function createMediaHandlers(prisma, _config) {
|
|
|
444
699
|
} catch {
|
|
445
700
|
}
|
|
446
701
|
}
|
|
447
|
-
await prisma.
|
|
702
|
+
await prisma[mediaModel].delete({ where: { id } });
|
|
448
703
|
return { success: true };
|
|
449
704
|
}
|
|
450
705
|
};
|
|
@@ -456,6 +711,7 @@ function createUploadHandler(prisma, config, storage) {
|
|
|
456
711
|
...config.upload.imageTypes,
|
|
457
712
|
...config.upload.videoTypes
|
|
458
713
|
];
|
|
714
|
+
const mediaModel = config.models.media;
|
|
459
715
|
return {
|
|
460
716
|
async handleUpload(file, uploaderId) {
|
|
461
717
|
if (!allowedTypes.includes(file.type)) {
|
|
@@ -470,7 +726,7 @@ function createUploadHandler(prisma, config, storage) {
|
|
|
470
726
|
}
|
|
471
727
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
472
728
|
const url = await storage.save(file.name, buffer, file.type);
|
|
473
|
-
await prisma.
|
|
729
|
+
await prisma[mediaModel].create({
|
|
474
730
|
data: {
|
|
475
731
|
filename: file.name,
|
|
476
732
|
path: url,
|
|
@@ -486,7 +742,8 @@ function createUploadHandler(prisma, config, storage) {
|
|
|
486
742
|
|
|
487
743
|
// src/handlers/auth.ts
|
|
488
744
|
import bcrypt2 from "bcryptjs";
|
|
489
|
-
function buildCredentialsProvider(prisma) {
|
|
745
|
+
function buildCredentialsProvider(prisma, config) {
|
|
746
|
+
const userModel = config?.models?.user ?? "user";
|
|
490
747
|
return {
|
|
491
748
|
credentials: {
|
|
492
749
|
email: {},
|
|
@@ -496,7 +753,7 @@ function buildCredentialsProvider(prisma) {
|
|
|
496
753
|
const email = credentials.email;
|
|
497
754
|
const password = credentials.password;
|
|
498
755
|
if (!email || !password) return null;
|
|
499
|
-
const user = await prisma.
|
|
756
|
+
const user = await prisma[userModel].findUnique({
|
|
500
757
|
where: { email }
|
|
501
758
|
});
|
|
502
759
|
if (!user) return null;
|