Skip to content

Commit 68b76a1

Browse files
authored
feat: add tag backup and fix bugs (#291)
* refactor(AddOrEdit.tsx): Implement role-based path selection Add role-based path selection using a dropdown for base path. Load paths from roles and update state accordingly. * 🔧 refactor(api): remove '/admin' prefix from label-related endpoints in api.ts * feat(manage.json/backup-restore.tsx): Add support for labels, roles, and label file bindings in backup-restore process.
1 parent 9e9ec0d commit 68b76a1

File tree

3 files changed

+256
-22
lines changed

3 files changed

+256
-22
lines changed

src/lang/en/manage.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"users": "Users",
1111
"storages": "Storages",
1212
"metas": "Metas",
13+
"labels": "Labels",
14+
"roles": "Roles",
15+
"label_file_bindings": "Label File Bindings",
1316
"profile": "Profile",
1417
"about": "About",
1518
"tasks": "Tasks",

src/pages/manage/backup-restore.tsx

Lines changed: 249 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ interface Data {
3030
users: User[]
3131
storages: Storage[]
3232
metas: Meta[]
33+
labels: any[]
34+
label_file_bindings: any[]
35+
roles: any[]
3336
}
3437
type LogType = "success" | "error" | "info"
3538
const LogMap = {
@@ -71,6 +74,34 @@ const BackupRestore = () => {
7174
setLog((prev) => [...prev, { type, msg }])
7275
logRef.scrollTop = logRef.scrollHeight
7376
}
77+
const [getLabelsLoading, getLabels] = useFetch(() => r.get("/label/list"))
78+
const [addLabelLoading, addLabel] = useFetch((label: any) =>
79+
r.post("/admin/label/create", label),
80+
)
81+
const [updateLabelLoading, updateLabel] = useFetch((label: any) =>
82+
r.post("/admin/label/update", label),
83+
)
84+
const [getLabelBindingsLoading, getLabelBindings] = useFetch(() =>
85+
r.get("/admin/label_file_binding/list"),
86+
)
87+
// const [addLabelBindingLoading, addLabelBinding] = useFetch((data: any) =>
88+
// r.post("/admin/label_file_binding/create", data)
89+
// )
90+
const [restoreLabelBindingsLoading, restoreLabelBindings] = useFetch(
91+
(payload: {
92+
keep_ids: boolean
93+
override: boolean
94+
bindings: any[]
95+
}): PEmptyResp => r.post("/admin/label_file_binding/restore", payload),
96+
)
97+
98+
const [getRolesLoading, getRoles] = useFetch(() => r.get("/admin/role/list"))
99+
const [addRoleLoading, addRole] = useFetch((data: any) =>
100+
r.post("/admin/role/create", data),
101+
)
102+
const [updateRoleLoading, updateRole] = useFetch((data: any) =>
103+
r.post("/admin/role/update", data),
104+
)
74105
const [getSettingsLoading, getSettings] = useFetch(
75106
(): PResp<any> => r.get("/admin/setting/list"),
76107
)
@@ -88,7 +119,10 @@ const BackupRestore = () => {
88119
getSettingsLoading() ||
89120
getUsersLoading() ||
90121
getMetasLoading() ||
91-
getStoragesLoading()
122+
getStoragesLoading() ||
123+
getLabelsLoading() ||
124+
getLabelBindingsLoading() ||
125+
getRolesLoading()
92126
)
93127
}
94128
function encrypt(data: any, key: string): string {
@@ -119,13 +153,19 @@ const BackupRestore = () => {
119153
users: [],
120154
storages: [],
121155
metas: [],
156+
labels: [],
157+
label_file_bindings: [],
158+
roles: [],
122159
}
123160
if (password() != "") allData.encrypted = encrypt("encrypted", password())
124161
for (const item of [
125162
{ name: "settings", fn: getSettings, page: false },
126163
{ name: "users", fn: getUsers, page: true },
127164
{ name: "storages", fn: getStorages, page: true },
128165
{ name: "metas", fn: getMetas, page: true },
166+
{ name: "labels", fn: getLabels, page: true },
167+
{ name: "label_file_bindings", fn: getLabelBindings, page: true },
168+
{ name: "roles", fn: getRoles, page: true },
129169
] as const) {
130170
const resp = await item.fn()
131171
handleRespWithoutNotify(
@@ -249,9 +289,15 @@ const BackupRestore = () => {
249289
addUserLoading() ||
250290
addStorageLoading() ||
251291
addMetaLoading() ||
292+
addLabelLoading() ||
293+
// addLabelBindingLoading() ||
294+
addRoleLoading() ||
252295
updateUserLoading() ||
253296
updateStorageLoading() ||
254-
updateMetaLoading()
297+
updateMetaLoading() ||
298+
updateLabelLoading() ||
299+
updateRoleLoading() ||
300+
restoreLabelBindingsLoading()
255301
)
256302
}
257303
const restore = async () => {
@@ -277,14 +323,21 @@ const BackupRestore = () => {
277323
appendLog(t("br.wrong_encrypt_password"), "error")
278324
return
279325
}
280-
const dataasarray = Object.values(data)
281-
for (let i = dataasarray.length - 4; i < dataasarray.length; i++) {
282-
const obj = dataasarray[i]
283-
console.log(obj)
284-
for (let a = 0; a < obj.length; a++) {
285-
const obj1 = obj[a]
286-
for (const key in obj1) {
287-
obj1[key] = decrypt(obj1[key], password(), false, encrypted)
326+
const encryptedArrays = [
327+
"settings",
328+
"users",
329+
"storages",
330+
"metas",
331+
"labels",
332+
"label_file_bindings",
333+
"roles",
334+
] as const
335+
for (const key of encryptedArrays) {
336+
const arr = (data as any)[key] || []
337+
for (let a = 0; a < arr.length; a++) {
338+
const obj1 = arr[a]
339+
for (const k in obj1) {
340+
obj1[k] = decrypt(obj1[k], password(), false, encrypted)
288341
}
289342
}
290343
}
@@ -318,6 +371,15 @@ const BackupRestore = () => {
318371
},
319372
)
320373
if (override()) {
374+
const lfbRows = (data.label_file_bindings || []).map((b: any) => ({
375+
...b,
376+
id: typeof b.id === "string" ? Number(b.id) : b.id,
377+
user_id:
378+
typeof b.user_id === "string" ? Number(b.user_id) : b.user_id,
379+
label_id:
380+
typeof b.label_id === "string" ? Number(b.label_id) : b.label_id,
381+
file_name: String(b.file_name ?? ""),
382+
}))
321383
await handleOvrData(
322384
data.users,
323385
getUsers,
@@ -342,20 +404,119 @@ const BackupRestore = () => {
342404
"path",
343405
"manage.sidemenu.metas",
344406
)
407+
await handleOvrData(
408+
data.labels,
409+
getLabels,
410+
addLabel,
411+
updateLabel,
412+
"id",
413+
"manage.sidemenu.labels",
414+
)
415+
if (lfbRows.length) {
416+
await handleRespWithoutNotify(
417+
await restoreLabelBindings({
418+
keep_ids: true,
419+
override: true,
420+
bindings: lfbRows,
421+
}),
422+
() => {
423+
appendLog(
424+
t("br.success_restore_item", {
425+
item: t("manage.sidemenu.label_file_bindings"),
426+
}),
427+
"success",
428+
)
429+
},
430+
(msg) => {
431+
appendLog(
432+
t("br.failed_restore_item", {
433+
item: t("manage.sidemenu.label_file_bindings"),
434+
}) +
435+
":" +
436+
msg,
437+
"error",
438+
)
439+
},
440+
)
441+
}
442+
const builtinRoleSet = new Set(["admin"])
443+
const rolesToProcess = (data.roles || []).filter((r: any) => {
444+
const rn = String(r?.name ?? "").toLowerCase()
445+
if (builtinRoleSet.has(rn)) {
446+
appendLog(
447+
t("br.success_restore_item", {
448+
item: t("manage.sidemenu.roles"),
449+
}) + ` - [${r.name}] skipped (builtin role)`,
450+
"info",
451+
)
452+
return false
453+
}
454+
return true
455+
})
456+
457+
await handleOvrData(
458+
rolesToProcess,
459+
getRoles,
460+
addRole,
461+
updateRole,
462+
"name",
463+
"manage.sidemenu.roles",
464+
)
345465
} else {
466+
const usersToCreate = (data.users || []).filter((u: any) => {
467+
const uname = String(u?.username ?? "").toLowerCase()
468+
if (uname === "admin" || uname === "guest") {
469+
appendLog(
470+
t("br.success_restore_item", {
471+
item: t("manage.sidemenu.users"),
472+
}) + ` - [${u.username}] skipped (builtin user)`,
473+
"info",
474+
)
475+
return false
476+
}
477+
return true
478+
})
479+
480+
for (const u of usersToCreate) {
481+
u.id = 0
482+
await handleRespWithoutNotify(
483+
await addUser(u),
484+
() => {
485+
appendLog(
486+
t("br.success_restore_item", {
487+
item: t("manage.sidemenu.users"),
488+
}) +
489+
"-" +
490+
`[${u.username}]`,
491+
"success",
492+
)
493+
},
494+
(msg) => {
495+
appendLog(
496+
t("br.failed_restore_item", {
497+
item: t("manage.sidemenu.users"),
498+
}) +
499+
` [ ${u.username} ] :` +
500+
msg,
501+
"error",
502+
)
503+
},
504+
)
505+
}
506+
346507
for (const item of [
347-
{ name: "users", fn: addUser, data: data.users, key: "username" },
348508
{
349509
name: "storages",
350510
fn: addStorage,
351511
data: data.storages,
352512
key: "mount_path",
353513
},
354514
{ name: "metas", fn: addMeta, data: data.metas, key: "path" },
515+
{ name: "labels", fn: addLabel, data: data.labels, key: "name" },
355516
] as const) {
356517
for (const itemData of item.data || []) {
357518
itemData.id = 0
358-
handleRespWithoutNotify(
519+
await handleRespWithoutNotify(
359520
await item.fn(itemData),
360521
() => {
361522
appendLog(
@@ -372,15 +533,87 @@ const BackupRestore = () => {
372533
t("br.failed_restore_item", {
373534
item: t(`manage.sidemenu.${item.name}`),
374535
}) +
375-
` [ ${(itemData as any)[item.key]} ] ` +
376-
":" +
536+
` [ ${(itemData as any)[item.key]} ] :` +
377537
msg,
378538
"error",
379539
)
380540
},
381541
)
382542
}
383543
}
544+
for (const role of data.roles || []) {
545+
const roleName = String(role?.name ?? "").toLowerCase()
546+
if (["admin", "guest", "general"].includes(roleName)) {
547+
appendLog(
548+
t("br.success_restore_item", {
549+
item: t("manage.sidemenu.roles"),
550+
}) + ` - [${role.name}] skipped (builtin role)`,
551+
"info",
552+
)
553+
continue
554+
}
555+
if ("id" in role) delete role.id
556+
await handleRespWithoutNotify(
557+
await addRole(role),
558+
() => {
559+
appendLog(
560+
t("br.success_restore_item", {
561+
item: t("manage.sidemenu.roles"),
562+
}) +
563+
"-" +
564+
`[${role.name}]`,
565+
"success",
566+
)
567+
},
568+
(msg) => {
569+
appendLog(
570+
t("br.failed_restore_item", {
571+
item: t("manage.sidemenu.roles"),
572+
}) +
573+
"-" +
574+
`[${role.name}]:` +
575+
msg,
576+
"error",
577+
)
578+
},
579+
)
580+
}
581+
const lfbRows = (data.label_file_bindings || []).map((b: any) => ({
582+
...b,
583+
id: typeof b.id === "string" ? Number(b.id) : b.id,
584+
user_id:
585+
typeof b.user_id === "string" ? Number(b.user_id) : b.user_id,
586+
label_id:
587+
typeof b.label_id === "string" ? Number(b.label_id) : b.label_id,
588+
file_name: String(b.file_name ?? ""),
589+
}))
590+
if (lfbRows.length) {
591+
await handleRespWithoutNotify(
592+
await restoreLabelBindings({
593+
keep_ids: true,
594+
override: false,
595+
bindings: lfbRows,
596+
}),
597+
() => {
598+
appendLog(
599+
t("br.success_restore_item", {
600+
item: t("manage.sidemenu.label_file_bindings"),
601+
}),
602+
"success",
603+
)
604+
},
605+
(msg) => {
606+
appendLog(
607+
t("br.failed_restore_item", {
608+
item: t("manage.sidemenu.label_file_bindings"),
609+
}) +
610+
":" +
611+
msg,
612+
"error",
613+
)
614+
},
615+
)
616+
}
384617
}
385618
appendLog(t("br.finish_restore"), "info")
386619
}
@@ -411,7 +644,7 @@ const BackupRestore = () => {
411644
</HStack>
412645
<FormControl w="$full" display="flex" flexDirection="column">
413646
<Flex w="$full" direction="column" gap="$1">
414-
<FormLabel>{t(`br.override`)}</FormLabel>
647+
<FormLabel for="restore-override">{t(`br.override`)}</FormLabel>
415648
<HopeSwitch
416649
id="restore-override"
417650
checked={override()}
@@ -420,7 +653,7 @@ const BackupRestore = () => {
420653
}
421654
></HopeSwitch>
422655

423-
<FormLabel>{t(`br.encrypt_password`)}</FormLabel>
656+
<FormLabel for="password">{t(`br.encrypt_password`)}</FormLabel>
424657
<Input
425658
id="password"
426659
type="password"

0 commit comments

Comments
 (0)