Skip to content

Commit

Permalink
feat: admin
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikvedvik committed Feb 27, 2024
1 parent eab4b8e commit 444d2f1
Show file tree
Hide file tree
Showing 15 changed files with 368 additions and 23 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ logs
.env.*
!.env.example

uploads
uploads
tmp

config
28 changes: 28 additions & 0 deletions components/MultiSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts" setup>
import { BccCheckbox } from "@bcc-code/design-library-vue";
defineProps<{
available: string[];
}>();
const value = defineModel<string[]>({ required: true });
const toggleCheckbox = (v: string) => {
if (value.value.includes(v)) {
value.value = value.value.filter((x) => x !== v);
} else {
value.value = [...value.value, v];
}
};
</script>
<template>
<div class="flex flex-col gap-1">
<div v-for="v in available">
<BccCheckbox
:label="v"
:model-value="value.includes(v) === true"
@update:model-value="toggleCheckbox(v)"
/>
</div>
</div>
</template>
98 changes: 98 additions & 0 deletions components/PermissionView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts" setup>
import type { Permissions } from "#imports";
import {
BccButton,
BccFormLabel,
BccToggle,
} from "@bcc-code/design-library-vue";
const props = defineProps<{
email: string;
permissions: Permissions;
}>();
defineEmits<{
remove: [];
}>();
const perms = ref<Permissions>(props.permissions);
watch(perms, () => {
$fetch("/api/permissions/set", {
method: "PUT",
body: {
email: props.email,
permissions: perms.value,
},
});
});
const admin = computed({
get: () => perms.value.admin === true,
set: (value: boolean) => {
perms.value = {
...perms.value,
admin: value,
};
},
});
const albums = computed({
get() {
return perms.value.bmm.albums;
},
set(v) {
perms.value = {
...perms.value,
bmm: {
...perms.value.bmm,
albums: v,
},
};
},
});
const languages = computed({
get() {
return perms.value.bmm.languages;
},
set(v) {
perms.value = {
...perms.value,
bmm: {
...perms.value.bmm,
languages: v,
},
};
},
});
</script>

<template>
<div class="flex flex-col rounded-lg border bg-white p-4">
<div class="flex justify-between">
<h3 class="text-lg">{{ email }}</h3>
<BccButton @click="$emit('remove')" size="sm">Remove</BccButton>
</div>
<div class="flex gap-4">
<div>
<BccFormLabel>Admin</BccFormLabel>
<BccToggle v-model="admin" />
</div>
<div>
<BccFormLabel>Albums</BccFormLabel>
<MultiSelector
:available="['fra-kaare', 'romans']"
v-model="albums"
/>
</div>
<div>
<BccFormLabel>Languages</BccFormLabel>
<MultiSelector
:available="['no', 'en', 'fr']"
v-model="languages"
/>
</div>
</div>
</div>
</template>
9 changes: 8 additions & 1 deletion components/bmm/BmmTrackSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,15 @@ const TrackView = (props: { track: Track }) => {
v-if="display"
:track="display"
/>
<p
v-else
class="flex cursor-pointer gap-2 rounded bg-slate-50"
@click="clicked = true"
>
<span class="rounded bg-slate-200 px-2">Not selected</span>
</p>
</div>
<div v-else class="flex flex-col gap-2">
<div v-else class="flex h-48 flex-col gap-2 overflow-y-auto">
<div v-for="t in tracks" class="flex">
<TrackView
:track="t"
Expand Down
4 changes: 4 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ export default defineNuxtConfig({
},
},
},
devServer: {
port: 80,
host: "0.0.0.0",
},
});
69 changes: 69 additions & 0 deletions pages/admin.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script lang="tsx" setup>
import type { Permissions } from "#imports";
import { BccButton, BccInput } from "@bcc-code/design-library-vue";
const { me } = useMe();
const permissions = ref<{
[key: string]: Permissions;
}>();
onMounted(async () => {
permissions.value = await $fetch("/api/permissions/list");
});
const newEmail = ref<string>();
const addEmail = async () => {
if (newEmail.value) {
await $fetch("/api/permissions/set", {
method: "PUT",
body: {
email: newEmail.value,
permissions: {
admin: false,
bmm: {
albums: [],
languages: [],
},
},
},
});
permissions.value = await $fetch("/api/permissions/list");
newEmail.value = "";
}
};
const removeEmail = async (email: string) => {
await $fetch("/api/permissions/set", {
method: "PUT",
body: {
email,
permissions: null,
},
});
permissions.value = await $fetch("/api/permissions/list");
};
</script>

<template>
<div class="flex h-screen w-screen" v-if="me?.admin">
<div
class="mx-auto w-full max-w-screen-md rounded-lg border-2 border-slate-950 bg-zinc-100 p-8 text-black"
>
<h3 class="text-lg">Admin</h3>
<div class="flex flex-col gap-4" v-if="permissions">
<PermissionView
v-for="[email, perms] in Object.entries(permissions)"
:email="email"
:permissions="perms"
@remove="removeEmail(email)"
/>
<div class="flex">
<BccInput v-model="newEmail" type="email"></BccInput>
<BccButton @click="addEmail">Add</BccButton>
</div>
</div>
</div>
</div>
</template>
15 changes: 10 additions & 5 deletions pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<script lang="ts" setup>
definePageMeta({
redirect: "/transcription",
});
</script>
<template>
<div class="flex flex-col gap-4">
<NuxtLink to="/upload/bmm" class="rounded bg-slate-700 p-2"
>BMM Upload</NuxtLink
>
<NuxtLink to="/transcription" class="rounded bg-slate-700 p-2"
>Transcription</NuxtLink
>
</div>
</template>
15 changes: 3 additions & 12 deletions pages/upload/bmm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,7 @@ const metadataIsSet = ref(false);
const selectedFile = ref<File | null>(null);
const me = ref<{
languages: string[];
albums: string[];
}>();
onMounted(async () => {
me.value = await $fetch("/api/bmm/me", {
method: "GET",
});
});
const { me } = useMe();
</script>

<template>
Expand All @@ -27,8 +18,8 @@ onMounted(async () => {
<BmmSingleMetadata
v-model="form"
@set="metadataIsSet = true"
:languages="me.languages"
:albums="me.albums"
:languages="me.bmm.languages"
:albums="me.bmm.albums"
/>
<div
class="flex flex-col gap-4 p-4 transition"
Expand Down
11 changes: 7 additions & 4 deletions server/api/bmm/me.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export default defineEventHandler(async (event) => {
return {
languages: ["nb", "en"],
albums: ["fra-kaare", "romans"],
};
const email = getHeader(event, "x-token-user-email");
if (!email) {
setResponseStatus(event, 401);
return;
}

return await getPermissions(email);
});
13 changes: 13 additions & 0 deletions server/api/bmm/tracks/[album].ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
export default defineEventHandler(async (event) => {
const email = getHeader(event, "x-token-user-email");

if (!email) {
setResponseStatus(event, 401);
return;
}

const perms = await getPermissions(email);

const album = getRouterParam(event, "album");

switch (album) {
case "fra-kaare":
if (!perms?.bmm.albums.includes("fra-kaare")) {
setResponseStatus(event, 403);
return;
}
return await getFraKaareTracks();
}
return [];
Expand Down
15 changes: 15 additions & 0 deletions server/api/permissions/list.get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default defineEventHandler(async (event) => {
const email = getHeader(event, "x-token-user-email");
if (!email) {
setResponseStatus(event, 401);
return;
}

const perms = await getPermissions(email);
if (!perms?.admin) {
setResponseStatus(event, 403);
return;
}

return await listPermissions();
});
26 changes: 26 additions & 0 deletions server/api/permissions/set.put.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Permissions } from "~/utils/permissions";

export default defineEventHandler(async (event) => {
const email = getHeader(event, "x-token-user-email");

if (!email) {
setResponseStatus(event, 401);
return;
}

const perms = await getPermissions(email);

if (!perms?.admin) {
setResponseStatus(event, 403);
return;
}

const request = await readBody<{
email: string;
permissions: Permissions;
}>(event);

console.log(request);

await setPermissions(request.email, request.permissions);
});
Loading

0 comments on commit 444d2f1

Please sign in to comment.