mirror of https://github.com/halo-dev/halo
parent
1cded7a581
commit
ca4e4bbeae
|
@ -144,9 +144,7 @@ async function loadCurrentUser() {
|
||||||
const { data: user } = await apiClient.user.getCurrentUserDetail();
|
const { data: user } = await apiClient.user.getCurrentUserDetail();
|
||||||
app.provide<User>("currentUser", user);
|
app.provide<User>("currentUser", user);
|
||||||
|
|
||||||
const { data: currentPermissions } = await apiClient.user.getPermissions(
|
const { data: currentPermissions } = await apiClient.user.getPermissions("-");
|
||||||
user.metadata.name
|
|
||||||
);
|
|
||||||
const roleStore = useRoleStore();
|
const roleStore = useRoleStore();
|
||||||
roleStore.$patch({
|
roleStore.$patch({
|
||||||
permissions: currentPermissions,
|
permissions: currentPermissions,
|
||||||
|
@ -174,7 +172,7 @@ async function loadCurrentUser() {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
async function initApp() {
|
async function initApp() {
|
||||||
// TODO 实验性特性
|
// TODO 实验性
|
||||||
const theme = localStorage.getItem("theme");
|
const theme = localStorage.getItem("theme");
|
||||||
if (theme) {
|
if (theme) {
|
||||||
document.body.classList.add(theme);
|
document.body.classList.add(theme);
|
||||||
|
|
|
@ -213,7 +213,7 @@ onMounted(handleFetchPlugin);
|
||||||
</VTag>
|
</VTag>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div v-permission="['system:plugins:manage']">
|
||||||
<VSwitch
|
<VSwitch
|
||||||
:model-value="isStarted"
|
:model-value="isStarted"
|
||||||
@change="handleChangePluginStatus"
|
@change="handleChangePluginStatus"
|
||||||
|
|
|
@ -74,7 +74,7 @@ onMounted(handleFetchPlugins);
|
||||||
<IconPlug class="mr-2 self-center" />
|
<IconPlug class="mr-2 self-center" />
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VButton type="secondary">
|
<VButton v-permission="['system:plugins:manage']" type="secondary">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconAddCircle class="h-full w-full" />
|
<IconAddCircle class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -274,13 +274,19 @@ onMounted(handleFetchPlugins);
|
||||||
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
||||||
{{ plugin.metadata.creationTimestamp }}
|
{{ plugin.metadata.creationTimestamp }}
|
||||||
</time>
|
</time>
|
||||||
<div class="flex items-center">
|
<div
|
||||||
|
v-permission="['system:plugins:manage']"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
<VSwitch
|
<VSwitch
|
||||||
:model-value="isStarted(plugin)"
|
:model-value="isStarted(plugin)"
|
||||||
@click="handleChangeStatus(plugin)"
|
@click="handleChangeStatus(plugin)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span class="cursor-pointer">
|
<span
|
||||||
|
v-permission="['system:plugins:manage']"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
<IconSettings @click.stop="handleRouteToDetail(plugin)" />
|
<IconSettings @click.stop="handleRouteToDetail(plugin)" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -15,11 +15,17 @@ export default definePlugin({
|
||||||
path: "",
|
path: "",
|
||||||
name: "Plugins",
|
name: "Plugins",
|
||||||
component: PluginList,
|
component: PluginList,
|
||||||
|
meta: {
|
||||||
|
permissions: ["system:plugins:view"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ":pluginName",
|
path: ":pluginName",
|
||||||
name: "PluginDetail",
|
name: "PluginDetail",
|
||||||
component: PluginDetail,
|
component: PluginDetail,
|
||||||
|
meta: {
|
||||||
|
permissions: ["system:plugins:view"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -154,7 +154,7 @@ onMounted(() => {
|
||||||
<IconShieldUser class="mr-2 self-center" />
|
<IconShieldUser class="mr-2 self-center" />
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VButton type="secondary">
|
<VButton v-permission="['system:roles:manage']" type="secondary">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconGitBranch class="h-full w-full" />
|
<IconGitBranch class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -345,7 +345,7 @@ onMounted(() => {
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
<div class="p-4">
|
<div v-permission="['system:roles:manage']" class="p-4">
|
||||||
<VButton
|
<VButton
|
||||||
:loading="formState.saving"
|
:loading="formState.saving"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
|
|
|
@ -56,7 +56,11 @@ onMounted(() => {
|
||||||
<IconShieldUser class="mr-2 self-center" />
|
<IconShieldUser class="mr-2 self-center" />
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VButton type="secondary" @click="createVisible = true">
|
<VButton
|
||||||
|
v-permission="['system:roles:manage']"
|
||||||
|
type="secondary"
|
||||||
|
@click="createVisible = true"
|
||||||
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconAddCircle class="h-full w-full" />
|
<IconAddCircle class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -198,7 +202,10 @@ onMounted(() => {
|
||||||
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
||||||
2020-01-07
|
2020-01-07
|
||||||
</time>
|
</time>
|
||||||
<span class="cursor-pointer">
|
<span
|
||||||
|
v-permission="['system:roles:manage']"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
<IconSettings />
|
<IconSettings />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,11 +14,17 @@ export default definePlugin({
|
||||||
path: "roles",
|
path: "roles",
|
||||||
name: "Roles",
|
name: "Roles",
|
||||||
component: RoleList,
|
component: RoleList,
|
||||||
|
meta: {
|
||||||
|
permissions: ["system:roles:view"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "roles/:name",
|
path: "roles/:name",
|
||||||
name: "RoleDetail",
|
name: "RoleDetail",
|
||||||
component: RoleDetail,
|
component: RoleDetail,
|
||||||
|
meta: {
|
||||||
|
permissions: ["system:roles:view"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -84,12 +84,14 @@ onMounted(() => {
|
||||||
<template>
|
<template>
|
||||||
<UserEditingModal
|
<UserEditingModal
|
||||||
v-model:visible="editingModal"
|
v-model:visible="editingModal"
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
:user="selectedUser"
|
:user="selectedUser"
|
||||||
@close="handleFetchUsers"
|
@close="handleFetchUsers"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UserPasswordChangeModal
|
<UserPasswordChangeModal
|
||||||
v-model:visible="passwordChangeModal"
|
v-model:visible="passwordChangeModal"
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
:user="selectedUser"
|
:user="selectedUser"
|
||||||
@close="handleFetchUsers"
|
@close="handleFetchUsers"
|
||||||
/>
|
/>
|
||||||
|
@ -100,13 +102,22 @@ onMounted(() => {
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<VSpace>
|
<VSpace>
|
||||||
<VButton :route="{ name: 'Roles' }" size="sm" type="default">
|
<VButton
|
||||||
|
v-permission="['system:roles:view']"
|
||||||
|
:route="{ name: 'Roles' }"
|
||||||
|
size="sm"
|
||||||
|
type="default"
|
||||||
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconUserFollow class="h-full w-full" />
|
<IconUserFollow class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
角色管理
|
角色管理
|
||||||
</VButton>
|
</VButton>
|
||||||
<VButton type="secondary" @click="editingModal = true">
|
<VButton
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
|
type="secondary"
|
||||||
|
@click="editingModal = true"
|
||||||
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<IconAddCircle class="h-full w-full" />
|
<IconAddCircle class="h-full w-full" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -126,6 +137,7 @@ onMounted(() => {
|
||||||
<div class="mr-4 hidden items-center sm:flex">
|
<div class="mr-4 hidden items-center sm:flex">
|
||||||
<input
|
<input
|
||||||
v-model="checkAll"
|
v-model="checkAll"
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
@ -252,6 +264,7 @@ onMounted(() => {
|
||||||
<div class="mr-4 hidden items-center sm:flex">
|
<div class="mr-4 hidden items-center sm:flex">
|
||||||
<input
|
<input
|
||||||
v-model="checkAll"
|
v-model="checkAll"
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
|
@ -304,10 +317,12 @@ onMounted(() => {
|
||||||
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
||||||
{{ user.metadata.creationTimestamp }}
|
{{ user.metadata.creationTimestamp }}
|
||||||
</time>
|
</time>
|
||||||
<span class="cursor-pointer">
|
<span
|
||||||
|
v-permission="['system:users:manage']"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
<FloatingDropdown>
|
<FloatingDropdown>
|
||||||
<IconSettings />
|
<IconSettings />
|
||||||
|
|
||||||
<template #popper>
|
<template #popper>
|
||||||
<div class="links-w-48 links-p-2">
|
<div class="links-w-48 links-p-2">
|
||||||
<VSpace class="links-w-full" direction="column">
|
<VSpace class="links-w-full" direction="column">
|
||||||
|
@ -319,7 +334,6 @@ onMounted(() => {
|
||||||
修改资料
|
修改资料
|
||||||
</VButton>
|
</VButton>
|
||||||
<VButton
|
<VButton
|
||||||
v-permission="['system:users:manage']"
|
|
||||||
block
|
block
|
||||||
@click="handleOpenPasswordChangeModal(user)"
|
@click="handleOpenPasswordChangeModal(user)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -33,6 +33,9 @@ export default definePlugin({
|
||||||
path: "",
|
path: "",
|
||||||
name: "Users",
|
name: "Users",
|
||||||
component: UserList,
|
component: UserList,
|
||||||
|
meta: {
|
||||||
|
permissions: ["system:users:view"],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function setupPermissionGuard(router: Router) {
|
||||||
const flag = hasPermission(
|
const flag = hasPermission(
|
||||||
Array.from(uiPermissions),
|
Array.from(uiPermissions),
|
||||||
meta.permissions as string[],
|
meta.permissions as string[],
|
||||||
false
|
true
|
||||||
);
|
);
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
next({ name: "Forbidden" });
|
next({ name: "Forbidden" });
|
||||||
|
|
|
@ -6,10 +6,10 @@ describe("hasPermission", () => {
|
||||||
const uiPermissions = ["system:post:manage", "system:post:view"];
|
const uiPermissions = ["system:post:manage", "system:post:view"];
|
||||||
|
|
||||||
expect(hasPermission(uiPermissions, ["system:post:manage"], false)).toBe(
|
expect(hasPermission(uiPermissions, ["system:post:manage"], false)).toBe(
|
||||||
false
|
true
|
||||||
);
|
);
|
||||||
expect(hasPermission(uiPermissions, ["system:post:view"], false)).toBe(
|
expect(hasPermission(uiPermissions, ["system:post:view"], false)).toBe(
|
||||||
false
|
true
|
||||||
);
|
);
|
||||||
expect(hasPermission(uiPermissions, ["system:post:view"], true)).toBe(true);
|
expect(hasPermission(uiPermissions, ["system:post:view"], true)).toBe(true);
|
||||||
expect(
|
expect(
|
||||||
|
|
|
@ -22,5 +22,5 @@ export function hasPermission(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!(!any && isEqual(uiPermissions, targetPermissions));
|
return !!(!any && isEqual(intersection, targetPermissions));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue