Skip to content

Commit 0e23976

Browse files
authored
feat(permissions): implement fine-grained permission control (#386)
1 parent 408043e commit 0e23976

File tree

11 files changed

+229
-98
lines changed

11 files changed

+229
-98
lines changed

src/lang/en/metas.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
{
22
"path": "Path",
33
"password": "Password",
4-
"write": "Write",
4+
"read_users": "Read Users",
5+
"read_users_help": "Only selected users with the required permission can read this path.",
6+
"write_users": "Write Users",
7+
"write_users_help": "Only selected users with the required permission can write this path.",
8+
"all_permitted_users": "All Permitted Users",
9+
"write": "Write Content Bypass",
10+
"write_help": "Bypasses user permission checks for content writes (create/upload/modify). USE WITH CAUTION.",
511
"hide": "Hide",
612
"readme": "Readme",
713
"readme_help": "Render a markdown at the bottom, support content or link",

src/lang/en/users.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"see_hides": "Can see hiddens",
44
"access_without_password": "Access without password",
55
"offline_download": "Add offline download tasks",
6-
"write": "Make dir or upload",
6+
"write_content": "Write content (Create / Upload / Modify)",
77
"rename": "Rename",
88
"move": "Move",
99
"copy": "Copy",

src/pages/home/folder/context-menu.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import { HStack, Icon, Text, useColorMode, Image } from "@hope-ui/solid"
55
import { operations } from "../toolbar/operations"
66
import { For, Show } from "solid-js"
77
import { bus, convertURL, notify } from "~/utils"
8-
import { ObjType, UserMethods, UserPermissions } from "~/types"
8+
import { ObjType, UserMethods } from "~/types"
99
import {
1010
getSettingBool,
1111
haveSelected,
1212
me,
13+
objStore,
1314
oneChecked,
1415
selectedObjs,
16+
userCan,
1517
} from "~/store"
1618
import { players } from "../previews/video_box"
1719
import { BsPlayCircleFill } from "solid-icons/bs"
@@ -50,13 +52,10 @@ export const ContextMenu = () => {
5052
theme={colorMode() !== "dark" ? "light" : "dark"}
5153
style="z-index: var(--hope-zIndices-popover)"
5254
>
53-
<For each={["rename", "move", "copy", "delete", "share"]}>
55+
<For each={["rename", "move", "copy", "delete"] as const}>
5456
{(name) => (
5557
<Item
56-
hidden={() => {
57-
const index = UserPermissions.findIndex((item) => item === name)
58-
return isShare() || !UserMethods.can(me(), index)
59-
}}
58+
hidden={!userCan(name) || !objStore.write || isShare()}
6059
onClick={() => {
6160
bus.emit("tool", name)
6261
}}
@@ -65,14 +64,20 @@ export const ContextMenu = () => {
6564
</Item>
6665
)}
6766
</For>
67+
<Item
68+
hidden={!userCan("share")}
69+
onClick={() => {
70+
bus.emit("tool", "share")
71+
}}
72+
>
73+
<ItemContent name="share" />
74+
</Item>
6875
<Item
6976
hidden={() => {
70-
const index = UserPermissions.findIndex(
71-
(item) => item === "decompress",
72-
)
7377
return (
7478
isShare() ||
75-
!UserMethods.can(me(), index) ||
79+
!userCan("decompress") ||
80+
!objStore.write ||
7681
selectedObjs().some((o) => o.is_dir) ||
7782
selectedObjs().some((o) => !isArchive(o.name))
7883
)

src/pages/home/previews/text-editor.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ function Editor(props: { data?: string | ArrayBuffer; contentType?: string }) {
5959
setValue(value)
6060
}}
6161
/>
62-
<Show when={userCan("write") || objStore.write}>
62+
<Show
63+
when={
64+
objStore.write &&
65+
(userCan("write_content") || objStore.write_content_bypass)
66+
}
67+
>
6368
<Button loading={loading()} onClick={onSave}>
6469
{t("global.save")}
6570
</Button>

src/pages/home/toolbar/Center.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { Box, HStack, useColorModeValue } from "@hope-ui/solid"
22
import { createMemo, For, Show } from "solid-js"
3-
import { checkboxOpen, haveSelected, objStore, selectAll, State } from "~/store"
3+
import {
4+
checkboxOpen,
5+
haveSelected,
6+
objStore,
7+
selectAll,
8+
State,
9+
userCan,
10+
} from "~/store"
411
import { CopyLink } from "./CopyLink"
512
import { CenterIcon } from "./Icon"
613
import { bus } from "~/utils"
@@ -27,7 +34,7 @@ export const Center = () => {
2734
w="max-content"
2835
color="$neutral11"
2936
as={Motion.div}
30-
initial={{ opacity: 0, scale: 0.9, x: "50% ", y: 10 }}
37+
initial={{ opacity: 0, scale: 0.9, x: "50%", y: 10 }}
3138
animate={{ opacity: 1, scale: 1, x: "50%", y: 0 }}
3239
exit={{ opacity: 0, scale: 0.9 }}
3340
// @ts-ignore
@@ -43,29 +50,32 @@ export const Center = () => {
4350
backdropFilter: "blur(8px)",
4451
}}
4552
>
46-
<Show when={!isShare()}>
53+
<Show when={!isShare() && objStore.write}>
4754
<For
48-
each={[
49-
"rename",
50-
"move",
51-
"copy",
52-
"delete",
53-
"share",
54-
"decompress",
55-
]}
55+
each={
56+
["rename", "move", "copy", "delete", "decompress"] as const
57+
}
5658
>
5759
{(name) => {
58-
return (
60+
return userCan(name) ? (
5961
<CenterIcon
6062
name={name}
6163
onClick={() => {
6264
bus.emit("tool", name)
6365
}}
6466
/>
65-
)
67+
) : null
6668
}}
6769
</For>
6870
</Show>
71+
<Show when={userCan("share")}>
72+
<CenterIcon
73+
name="share"
74+
onClick={() => {
75+
bus.emit("tool", "share")
76+
}}
77+
/>
78+
</Show>
6979
<CopyLink />
7080
<Download />
7181
<CenterIcon

src/pages/home/toolbar/CopyMove.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ import { Checkbox, createDisclosure, VStack, Button } from "@hope-ui/solid"
22
import { createSignal, onCleanup } from "solid-js"
33
import { ModalFolderChoose, FolderTreeHandler } from "~/components"
44
import { useFetch, usePath, useRouter, useT } from "~/hooks"
5-
import { me, selectedObjs } from "~/store"
5+
import { selectedObjs, userCan } from "~/store"
66
import { bus, fsCopy, fsMove, handleRespWithNotifySuccess } from "~/utils"
77
import { CgFolderAdd } from "solid-icons/cg"
8-
import { UserMethods, UserPermissions } from "~/types"
98

109
export const CreateFolderButton = (props: { handler?: FolderTreeHandler }) => {
11-
if (!UserMethods.can(me(), UserPermissions.indexOf("write"))) {
10+
if (!userCan("write_content")) {
1211
return null
1312
}
1413
const t = useT()

src/pages/home/toolbar/Right.tsx

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,21 @@ export const Right = () => {
5959
transition={{ duration: 0.2 }}
6060
>
6161
<VStack spacing="$1" class="left-toolbar-in">
62-
<RightIcon
63-
as={RiSystemRefreshLine}
64-
tips="refresh"
65-
onClick={() => {
66-
refresh(undefined, true)
67-
}}
68-
/>
6962
<Show
7063
when={
71-
isFolder() && !isShare() && (userCan("write") || objStore.write)
64+
isFolder() &&
65+
!isShare() &&
66+
(userCan("write_content") || objStore.write_content_bypass) &&
67+
objStore.write
7268
}
7369
>
74-
{/* <Add /> */}
70+
<RightIcon
71+
as={RiSystemRefreshLine}
72+
tips="refresh"
73+
onClick={() => {
74+
refresh(undefined, true)
75+
}}
76+
/>
7577
<RightIcon
7678
as={operations.new_file.icon}
7779
tips="new_file"
@@ -87,20 +89,38 @@ export const Right = () => {
8789
bus.emit("tool", "mkdir")
8890
}}
8991
/>
92+
</Show>
93+
<Show
94+
when={
95+
isFolder() && !isShare() && userCan("move") && objStore.write
96+
}
97+
>
9098
<RightIcon
9199
as={operations.recursive_move.icon}
92100
tips="recursive_move"
93101
onClick={() => {
94102
bus.emit("tool", "recursiveMove")
95103
}}
96104
/>
105+
</Show>
106+
<Show
107+
when={
108+
isFolder() && !isShare() && userCan("delete") && objStore.write
109+
}
110+
>
97111
<RightIcon
98112
as={operations.remove_empty_directory.icon}
99113
tips="remove_empty_directory"
100114
onClick={() => {
101115
bus.emit("tool", "removeEmptyDirectory")
102116
}}
103117
/>
118+
</Show>
119+
<Show
120+
when={
121+
isFolder() && !isShare() && userCan("rename") && objStore.write
122+
}
123+
>
104124
<RightIcon
105125
as={operations.batch_rename.icon}
106126
tips="batch_rename"
@@ -109,6 +129,15 @@ export const Right = () => {
109129
bus.emit("tool", "batchRename")
110130
}}
111131
/>
132+
</Show>
133+
<Show
134+
when={
135+
isFolder() &&
136+
!isShare() &&
137+
(userCan("write_content") || objStore.write_content_bypass) &&
138+
objStore.write
139+
}
140+
>
112141
<RightIcon
113142
as={AiOutlineCloudUpload}
114143
tips="upload"
@@ -118,7 +147,12 @@ export const Right = () => {
118147
/>
119148
</Show>
120149
<Show
121-
when={isFolder() && !isShare() && userCan("offline_download")}
150+
when={
151+
isFolder() &&
152+
!isShare() &&
153+
userCan("offline_download") &&
154+
objStore.write
155+
}
122156
>
123157
<RightIcon
124158
as={IoMagnetOutline}

0 commit comments

Comments
 (0)