init
This commit is contained in:
@@ -1,103 +0,0 @@
|
||||
<template>
|
||||
<v-container class="fill-height d-flex flex-column justify-center" max-width="1100">
|
||||
<div>
|
||||
<v-img
|
||||
class="mb-4 font-weight-bold"
|
||||
height="150"
|
||||
src="@/assets/logo.png"
|
||||
/>
|
||||
|
||||
<div class="mb-8 text-center">
|
||||
<div class="text-body-medium font-weight-light mb-n1">Welcome to</div>
|
||||
<div class="text-display-medium font-weight-bold">Vuetify</div>
|
||||
</div>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card
|
||||
class="py-4"
|
||||
color="surface-variant"
|
||||
image="https://cdn.vuetifyjs.com/docs/images/one/create/feature.png"
|
||||
rounded="lg"
|
||||
variant="tonal"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-avatar class="ml-2 mr-4" icon="mdi-rocket-launch-outline" size="60" variant="tonal"/>
|
||||
</template>
|
||||
|
||||
<template #image>
|
||||
<v-img position="top right"/>
|
||||
</template>
|
||||
|
||||
<template #title>
|
||||
<div class="my-title my-uppercase text-headline-medium font-weight-bold">Get started</div>
|
||||
</template>
|
||||
|
||||
<template #subtitle>
|
||||
<div class="text-body-large">
|
||||
Change this page by updating
|
||||
<v-kbd>{{
|
||||
`
|
||||
|
||||
<HelloWorld/>
|
||||
` }}
|
||||
</v-kbd>
|
||||
in
|
||||
<v-kbd>components/HelloWorld.vue</v-kbd>
|
||||
.
|
||||
</div>
|
||||
</template>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col v-for="link in links" :key="link.href" cols="6">
|
||||
<v-card
|
||||
:href="link.href"
|
||||
:subtitle="link.subtitle"
|
||||
:title="link.title"
|
||||
append-icon="mdi-open-in-new"
|
||||
class="py-4"
|
||||
color="surface-variant"
|
||||
rel="noopener noreferrer"
|
||||
rounded="lg"
|
||||
target="_blank"
|
||||
variant="tonal"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-avatar :icon="link.icon" class="ml-2 mr-4" size="60" variant="tonal"/>
|
||||
</template>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const links = [
|
||||
{
|
||||
href: 'https://vuetifyjs.com/',
|
||||
icon: 'mdi-text-box-outline',
|
||||
subtitle: 'Learn about all things Vuetify in our documentation.',
|
||||
title: 'Documentation',
|
||||
},
|
||||
{
|
||||
href: 'https://vuetifyjs.com/introduction/why-vuetify/#feature-guides',
|
||||
icon: 'mdi-star-circle-outline',
|
||||
subtitle: 'Explore available framework Features.',
|
||||
title: 'Features',
|
||||
},
|
||||
{
|
||||
href: 'https://vuetifyjs.com/components/all',
|
||||
icon: 'mdi-widgets-outline',
|
||||
subtitle: 'Discover components in the API Explorer.',
|
||||
title: 'Components',
|
||||
},
|
||||
{
|
||||
href: 'https://discord.vuetifyjs.com',
|
||||
icon: 'mdi-account-group-outline',
|
||||
subtitle: 'Connect with Vuetify developers.',
|
||||
title: 'Community',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
# Components
|
||||
|
||||
Vue template files in this folder are automatically imported.
|
||||
|
||||
## 🚀 Usage
|
||||
|
||||
Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it.
|
||||
|
||||
The following example assumes a component located at `src/components/MyComponent.vue`:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<MyComponent />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//
|
||||
</script>
|
||||
```
|
||||
|
||||
When your template is rendered, the component's import will automatically be inlined, which renders to this:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<MyComponent />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MyComponent from '@/components/MyComponent.vue'
|
||||
</script>
|
||||
```
|
||||
@@ -0,0 +1,181 @@
|
||||
<!--
|
||||
Exemple d'utilisation :
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import ChannelPermissionEditor from '@/components/permissions/ChannelPermissionEditor.vue'
|
||||
import {
|
||||
toChannelPermissionMask,
|
||||
type ChannelPermissionMask,
|
||||
} from '@/types/permissions'
|
||||
|
||||
const permissions = ref<ChannelPermissionMask>(
|
||||
toChannelPermissionMask(0),
|
||||
)
|
||||
|
||||
function saveChannelPermissions(
|
||||
value: ChannelPermissionMask,
|
||||
) {
|
||||
permissions.value = value
|
||||
// Appel usePermissions().setChannelRolePermission(...)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ChannelPermissionEditor
|
||||
v-model="permissions"
|
||||
@save="saveChannelPermissions"
|
||||
/>
|
||||
</template>
|
||||
-->
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import {
|
||||
CHANNEL_PERMISSION_DEFINITIONS,
|
||||
type ChannelPermissionMask,
|
||||
grantChannelPermission,
|
||||
revokeChannelPermission,
|
||||
} from '@/types/permissions'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue: ChannelPermissionMask
|
||||
loading?: boolean
|
||||
readonly?: boolean
|
||||
title?: string
|
||||
}>(), {
|
||||
loading: false,
|
||||
readonly: false,
|
||||
title: 'Permissions du canal',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [permissions: ChannelPermissionMask]
|
||||
save: [permissions: ChannelPermissionMask]
|
||||
}>()
|
||||
|
||||
const permissions = ref<ChannelPermissionMask>(props.modelValue)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(value) => {
|
||||
permissions.value = value
|
||||
},
|
||||
)
|
||||
|
||||
const permissionGroups = computed(() => {
|
||||
const groups = new Map<
|
||||
string,
|
||||
typeof CHANNEL_PERMISSION_DEFINITIONS
|
||||
>()
|
||||
|
||||
for (const permission of CHANNEL_PERMISSION_DEFINITIONS) {
|
||||
const group = groups.get(permission.category) ?? []
|
||||
group.push(permission)
|
||||
groups.set(permission.category, group)
|
||||
}
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
chat: 'Discussion',
|
||||
management: 'Gestion',
|
||||
voice: 'Vocal',
|
||||
}
|
||||
|
||||
return Array.from(groups.entries()).map(([key, items]) => ({
|
||||
key,
|
||||
label: labels[key] ?? key,
|
||||
permissions: items,
|
||||
}))
|
||||
})
|
||||
|
||||
function isEnabled(bit: ChannelPermissionMask): boolean {
|
||||
return (permissions.value & bit) === bit
|
||||
}
|
||||
|
||||
function updatePermission(
|
||||
bit: ChannelPermissionMask,
|
||||
enabled: boolean,
|
||||
): void {
|
||||
if (props.readonly || props.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
permissions.value = enabled
|
||||
? grantChannelPermission(permissions.value, bit)
|
||||
: revokeChannelPermission(permissions.value, bit)
|
||||
|
||||
emit('update:modelValue', permissions.value)
|
||||
}
|
||||
|
||||
function save(): void {
|
||||
if (props.readonly || props.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('save', permissions.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>{{ title }}</v-card-title>
|
||||
|
||||
<v-divider/>
|
||||
|
||||
<v-card-text>
|
||||
<v-expansion-panels multiple>
|
||||
<v-expansion-panel
|
||||
v-for="group in permissionGroups"
|
||||
:key="group.key"
|
||||
:title="group.label"
|
||||
>
|
||||
<v-expansion-panel-text>
|
||||
<v-list lines="two">
|
||||
<v-list-item
|
||||
v-for="permission in group.permissions"
|
||||
:key="permission.key"
|
||||
class="px-0"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-checkbox
|
||||
:disabled="readonly || loading"
|
||||
:model-value="isEnabled(permission.bit)"
|
||||
color="primary"
|
||||
hide-details
|
||||
@update:model-value="
|
||||
updatePermission(permission.bit, Boolean($event))
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list-item-title>
|
||||
{{ permission.label }}
|
||||
</v-list-item-title>
|
||||
|
||||
<v-list-item-subtitle
|
||||
v-if="permission.description"
|
||||
>
|
||||
{{ permission.description }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider/>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn
|
||||
:disabled="readonly || loading"
|
||||
:loading="loading"
|
||||
color="primary"
|
||||
@click="save"
|
||||
>
|
||||
Enregistrer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!--
|
||||
Exemple d'utilisation :
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import ServerPermissionEditor from '@/components/permissions/ServerPermissionEditor.vue'
|
||||
import {
|
||||
toServerPermissionMask,
|
||||
type ServerPermissionMask,
|
||||
} from '@/types/permissions'
|
||||
|
||||
const permissions = ref<ServerPermissionMask>(
|
||||
toServerPermissionMask(0),
|
||||
)
|
||||
|
||||
function saveServerPermissions(
|
||||
value: ServerPermissionMask,
|
||||
) {
|
||||
permissions.value = value
|
||||
// Appel usePermissions().setServerRolePermission(...)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ServerPermissionEditor
|
||||
v-model="permissions"
|
||||
@save="saveServerPermissions"
|
||||
/>
|
||||
</template>
|
||||
-->
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import {
|
||||
grantServerPermission,
|
||||
revokeServerPermission,
|
||||
SERVER_PERMISSION_DEFINITIONS,
|
||||
type ServerPermissionMask,
|
||||
} from '@/types/permissions'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue: ServerPermissionMask
|
||||
loading?: boolean
|
||||
readonly?: boolean
|
||||
title?: string
|
||||
}>(), {
|
||||
loading: false,
|
||||
readonly: false,
|
||||
title: 'Permissions du serveur',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [permissions: ServerPermissionMask]
|
||||
save: [permissions: ServerPermissionMask]
|
||||
}>()
|
||||
|
||||
const permissions = ref<ServerPermissionMask>(props.modelValue)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(value) => {
|
||||
permissions.value = value
|
||||
},
|
||||
)
|
||||
|
||||
const permissionGroups = computed(() => {
|
||||
const groups = new Map<
|
||||
string,
|
||||
typeof SERVER_PERMISSION_DEFINITIONS
|
||||
>()
|
||||
|
||||
for (const permission of SERVER_PERMISSION_DEFINITIONS) {
|
||||
const group = groups.get(permission.category) ?? []
|
||||
group.push(permission)
|
||||
groups.set(permission.category, group)
|
||||
}
|
||||
|
||||
return Array.from(groups.entries()).map(([key, items]) => ({
|
||||
key,
|
||||
label: key === 'management' ? 'Gestion' : 'Membres',
|
||||
permissions: items,
|
||||
}))
|
||||
})
|
||||
|
||||
function isEnabled(bit: ServerPermissionMask): boolean {
|
||||
return (permissions.value & bit) === bit
|
||||
}
|
||||
|
||||
function updatePermission(
|
||||
bit: ServerPermissionMask,
|
||||
enabled: boolean,
|
||||
): void {
|
||||
if (props.readonly || props.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
permissions.value = enabled
|
||||
? grantServerPermission(permissions.value, bit)
|
||||
: revokeServerPermission(permissions.value, bit)
|
||||
|
||||
emit('update:modelValue', permissions.value)
|
||||
}
|
||||
|
||||
function save(): void {
|
||||
if (props.readonly || props.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('save', permissions.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>{{ title }}</v-card-title>
|
||||
|
||||
<v-divider/>
|
||||
|
||||
<v-card-text>
|
||||
<v-expansion-panels multiple>
|
||||
<v-expansion-panel
|
||||
v-for="group in permissionGroups"
|
||||
:key="group.key"
|
||||
:title="group.label"
|
||||
>
|
||||
<v-expansion-panel-text>
|
||||
<v-list lines="two">
|
||||
<v-list-item
|
||||
v-for="permission in group.permissions"
|
||||
:key="permission.key"
|
||||
class="px-0"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-checkbox
|
||||
:disabled="readonly || loading"
|
||||
:model-value="isEnabled(permission.bit)"
|
||||
color="primary"
|
||||
hide-details
|
||||
@update:model-value="
|
||||
updatePermission(permission.bit, Boolean($event))
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list-item-title>
|
||||
{{ permission.label }}
|
||||
</v-list-item-title>
|
||||
|
||||
<v-list-item-subtitle
|
||||
v-if="permission.description"
|
||||
>
|
||||
{{ permission.description }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider/>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
|
||||
<v-btn
|
||||
:disabled="readonly || loading"
|
||||
:loading="loading"
|
||||
color="primary"
|
||||
@click="save"
|
||||
>
|
||||
Enregistrer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
@@ -0,0 +1,235 @@
|
||||
import {useApi} from '@/composables/useApi'
|
||||
import {
|
||||
type ChannelRolePermission,
|
||||
type ChannelRolePermissionDto,
|
||||
channelRolePermissionFromDto,
|
||||
type ChannelUserPermission,
|
||||
type ChannelUserPermissionDto,
|
||||
channelUserPermissionFromDto,
|
||||
type PermissionMaskInput,
|
||||
permissionMaskToJson,
|
||||
type ServerRolePermission,
|
||||
type ServerRolePermissionDto,
|
||||
serverRolePermissionFromDto,
|
||||
type ServerUserPermission,
|
||||
type ServerUserPermissionDto,
|
||||
serverUserPermissionFromDto,
|
||||
} from '@/types/permissions'
|
||||
|
||||
export function usePermissions() {
|
||||
const api = useApi()
|
||||
|
||||
async function parseResponse<T>(response: Response): Promise<T> {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => null)
|
||||
|
||||
throw new Error(
|
||||
error?.message || 'Erreur lors de la gestion des permissions',
|
||||
)
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return undefined as T
|
||||
}
|
||||
|
||||
return response.json() as Promise<T>
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Permissions serveur - utilisateur
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function getServerUserPermission(
|
||||
serverId: string,
|
||||
userId: string,
|
||||
): Promise<ServerUserPermission> {
|
||||
const response = await api.get(
|
||||
`/servers/${serverId}/permissions/users/${userId}`,
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ServerUserPermissionDto>(response)
|
||||
|
||||
return serverUserPermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function setServerUserPermission(
|
||||
serverId: string,
|
||||
userId: string,
|
||||
permissions: PermissionMaskInput,
|
||||
): Promise<ServerUserPermission> {
|
||||
const response = await api.put(
|
||||
`/servers/${serverId}/permissions/users/${userId}`,
|
||||
{
|
||||
permissions: permissionMaskToJson(permissions),
|
||||
},
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ServerUserPermissionDto>(response)
|
||||
|
||||
return serverUserPermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function removeServerUserPermission(
|
||||
serverId: string,
|
||||
userId: string,
|
||||
): Promise<void> {
|
||||
const response = await api.delete(
|
||||
`/servers/${serverId}/permissions/users/${userId}`,
|
||||
)
|
||||
|
||||
await parseResponse<void>(response)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Permissions serveur - rôle
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function getServerRolePermission(
|
||||
serverId: string,
|
||||
roleId: string,
|
||||
): Promise<ServerRolePermission> {
|
||||
const response = await api.get(
|
||||
`/servers/${serverId}/permissions/roles/${roleId}`,
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ServerRolePermissionDto>(response)
|
||||
|
||||
return serverRolePermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function setServerRolePermission(
|
||||
serverId: string,
|
||||
roleId: string,
|
||||
permissions: PermissionMaskInput,
|
||||
): Promise<ServerRolePermission> {
|
||||
const response = await api.put(
|
||||
`/servers/${serverId}/permissions/roles/${roleId}`,
|
||||
{
|
||||
permissions: permissionMaskToJson(permissions),
|
||||
},
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ServerRolePermissionDto>(response)
|
||||
|
||||
return serverRolePermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function removeServerRolePermission(
|
||||
serverId: string,
|
||||
roleId: string,
|
||||
): Promise<void> {
|
||||
const response = await api.delete(
|
||||
`/servers/${serverId}/permissions/roles/${roleId}`,
|
||||
)
|
||||
|
||||
await parseResponse<void>(response)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Permissions canal - utilisateur
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function getChannelUserPermission(
|
||||
channelId: string,
|
||||
userId: string,
|
||||
): Promise<ChannelUserPermission> {
|
||||
const response = await api.get(
|
||||
`/channels/${channelId}/permissions/users/${userId}`,
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ChannelUserPermissionDto>(response)
|
||||
|
||||
return channelUserPermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function setChannelUserPermission(
|
||||
channelId: string,
|
||||
userId: string,
|
||||
permissions: PermissionMaskInput,
|
||||
): Promise<ChannelUserPermission> {
|
||||
const response = await api.put(
|
||||
`/channels/${channelId}/permissions/users/${userId}`,
|
||||
{
|
||||
permissions: permissionMaskToJson(permissions),
|
||||
},
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ChannelUserPermissionDto>(response)
|
||||
|
||||
return channelUserPermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function removeChannelUserPermission(
|
||||
channelId: string,
|
||||
userId: string,
|
||||
): Promise<void> {
|
||||
const response = await api.delete(
|
||||
`/channels/${channelId}/permissions/users/${userId}`,
|
||||
)
|
||||
|
||||
await parseResponse<void>(response)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Permissions canal - rôle
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function getChannelRolePermission(
|
||||
channelId: string,
|
||||
roleId: string,
|
||||
): Promise<ChannelRolePermission> {
|
||||
const response = await api.get(
|
||||
`/channels/${channelId}/permissions/roles/${roleId}`,
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ChannelRolePermissionDto>(response)
|
||||
|
||||
return channelRolePermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function setChannelRolePermission(
|
||||
channelId: string,
|
||||
roleId: string,
|
||||
permissions: PermissionMaskInput,
|
||||
): Promise<ChannelRolePermission> {
|
||||
const response = await api.put(
|
||||
`/channels/${channelId}/permissions/roles/${roleId}`,
|
||||
{
|
||||
permissions: permissionMaskToJson(permissions),
|
||||
},
|
||||
)
|
||||
|
||||
const dto = await parseResponse<ChannelRolePermissionDto>(response)
|
||||
|
||||
return channelRolePermissionFromDto(dto)
|
||||
}
|
||||
|
||||
async function removeChannelRolePermission(
|
||||
channelId: string,
|
||||
roleId: string,
|
||||
): Promise<void> {
|
||||
const response = await api.delete(
|
||||
`/channels/${channelId}/permissions/roles/${roleId}`,
|
||||
)
|
||||
|
||||
await parseResponse<void>(response)
|
||||
}
|
||||
|
||||
return {
|
||||
getServerUserPermission,
|
||||
setServerUserPermission,
|
||||
removeServerUserPermission,
|
||||
|
||||
getServerRolePermission,
|
||||
setServerRolePermission,
|
||||
removeServerRolePermission,
|
||||
|
||||
getChannelUserPermission,
|
||||
setChannelUserPermission,
|
||||
removeChannelUserPermission,
|
||||
|
||||
getChannelRolePermission,
|
||||
setChannelRolePermission,
|
||||
removeChannelRolePermission,
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,39 @@
|
||||
<script lang="ts" setup>
|
||||
import {ref} from 'vue'
|
||||
import ServerPermissionEditor from '@/components/permissions/ServerPermissionEditor.vue'
|
||||
import ChannelPermissionEditor from '@/components/permissions/ChannelPermissionEditor.vue'
|
||||
import {
|
||||
type ChannelPermissionMask,
|
||||
type ServerPermissionMask,
|
||||
toChannelPermissionMask,
|
||||
toServerPermissionMask,
|
||||
} from '@/types/permissions'
|
||||
|
||||
const serverPermissions = ref<ServerPermissionMask>(
|
||||
toServerPermissionMask(0),
|
||||
)
|
||||
|
||||
const channelPermissions = ref<ChannelPermissionMask>(
|
||||
toChannelPermissionMask(0),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<ServerPermissionEditor
|
||||
v-model="serverPermissions"
|
||||
title="Test des permissions serveur"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<v-col cols="12" md="6">
|
||||
<ChannelPermissionEditor
|
||||
v-model="channelPermissions"
|
||||
title="Test des permissions canal"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<HelloWorld />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import HelloWorld from '@/components/HelloWorld.vue'
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Hello
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,445 @@
|
||||
export type PermissionMaskInput = bigint | number | string
|
||||
|
||||
export type ServerPermissionMask = bigint & {
|
||||
readonly __brand: 'ServerPermissionMask'
|
||||
}
|
||||
|
||||
export type ChannelPermissionMask = bigint & {
|
||||
readonly __brand: 'ChannelPermissionMask'
|
||||
}
|
||||
|
||||
export interface ServerPermissionDefinition {
|
||||
key: string
|
||||
label: string
|
||||
description?: string
|
||||
bit: ServerPermissionMask
|
||||
category: 'management' | 'members'
|
||||
}
|
||||
|
||||
export interface ChannelPermissionDefinition {
|
||||
key: string
|
||||
label: string
|
||||
description?: string
|
||||
bit: ChannelPermissionMask
|
||||
category: 'chat' | 'voice' | 'management'
|
||||
}
|
||||
|
||||
export interface ServerUserPermission {
|
||||
id: string
|
||||
server_id: string
|
||||
user_id: string
|
||||
permissions: ServerPermissionMask
|
||||
}
|
||||
|
||||
export interface ServerRolePermission {
|
||||
id: string
|
||||
server_id: string
|
||||
role_id: string
|
||||
permissions: ServerPermissionMask
|
||||
}
|
||||
|
||||
export interface ChannelUserPermission {
|
||||
id: string
|
||||
channel_id: string
|
||||
user_id: string
|
||||
permissions: ChannelPermissionMask
|
||||
}
|
||||
|
||||
export interface ChannelRolePermission {
|
||||
id: string
|
||||
channel_id: string
|
||||
role_id: string
|
||||
permissions: ChannelPermissionMask
|
||||
}
|
||||
|
||||
export interface ServerUserPermissionDto {
|
||||
id: string
|
||||
server_id: string
|
||||
user_id: string
|
||||
permissions: number | string
|
||||
}
|
||||
|
||||
export interface ServerRolePermissionDto {
|
||||
id: string
|
||||
server_id: string
|
||||
role_id: string
|
||||
permissions: number | string
|
||||
}
|
||||
|
||||
export interface ChannelUserPermissionDto {
|
||||
id: string
|
||||
channel_id: string
|
||||
user_id: string
|
||||
permissions: number | string
|
||||
}
|
||||
|
||||
export interface ChannelRolePermissionDto {
|
||||
id: string
|
||||
channel_id: string
|
||||
role_id: string
|
||||
permissions: number | string
|
||||
}
|
||||
|
||||
function asServerPermissionMask(value: bigint): ServerPermissionMask {
|
||||
return value as ServerPermissionMask
|
||||
}
|
||||
|
||||
function asChannelPermissionMask(value: bigint): ChannelPermissionMask {
|
||||
return value as ChannelPermissionMask
|
||||
}
|
||||
|
||||
function toBigInt(value: PermissionMaskInput): bigint {
|
||||
if (typeof value === 'bigint') {
|
||||
return value
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
if (!Number.isSafeInteger(value) || value < 0) {
|
||||
throw new Error(`Invalid permission mask: ${value}`)
|
||||
}
|
||||
|
||||
return BigInt(value)
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(value)) {
|
||||
throw new Error(`Invalid permission mask: ${value}`)
|
||||
}
|
||||
|
||||
return BigInt(value)
|
||||
}
|
||||
|
||||
export function toServerPermissionMask(
|
||||
value: PermissionMaskInput,
|
||||
): ServerPermissionMask {
|
||||
return asServerPermissionMask(toBigInt(value))
|
||||
}
|
||||
|
||||
export function toChannelPermissionMask(
|
||||
value: PermissionMaskInput,
|
||||
): ChannelPermissionMask {
|
||||
return asChannelPermissionMask(toBigInt(value))
|
||||
}
|
||||
|
||||
export const SERVER_PERMISSIONS = {
|
||||
MANAGE_SERVER: asServerPermissionMask(1n << 0n),
|
||||
MANAGE_ROLES: asServerPermissionMask(1n << 1n),
|
||||
MANAGE_CATEGORIES: asServerPermissionMask(1n << 2n),
|
||||
MANAGE_CHANNELS: asServerPermissionMask(1n << 3n),
|
||||
KICK_MEMBERS: asServerPermissionMask(1n << 4n),
|
||||
BAN_MEMBERS: asServerPermissionMask(1n << 5n),
|
||||
MANAGE_MEMBERS: asServerPermissionMask(1n << 6n),
|
||||
VIEW_MEMBERS: asServerPermissionMask(1n << 7n),
|
||||
} as const satisfies Record<string, ServerPermissionMask>
|
||||
|
||||
export const CHANNEL_PERMISSIONS = {
|
||||
READ_CHANNEL: asChannelPermissionMask(1n << 0n),
|
||||
SEND_MESSAGE: asChannelPermissionMask(1n << 1n),
|
||||
EDIT_OWN_MESSAGE: asChannelPermissionMask(1n << 2n),
|
||||
DELETE_OWN_MESSAGE: asChannelPermissionMask(1n << 3n),
|
||||
EDIT_OTHERS_MESSAGES: asChannelPermissionMask(1n << 4n),
|
||||
DELETE_OTHERS_MESSAGES: asChannelPermissionMask(1n << 5n),
|
||||
ADD_REACTIONS: asChannelPermissionMask(1n << 6n),
|
||||
ATTACH_FILES: asChannelPermissionMask(1n << 7n),
|
||||
MANAGE_CHANNEL: asChannelPermissionMask(1n << 8n),
|
||||
MANAGE_MESSAGES: asChannelPermissionMask(1n << 10n),
|
||||
JOIN_VOICE: asChannelPermissionMask(1n << 30n),
|
||||
SPEAK: asChannelPermissionMask(1n << 31n),
|
||||
STREAM: asChannelPermissionMask(1n << 32n),
|
||||
MUTE_SELF: asChannelPermissionMask(1n << 33n),
|
||||
MUTE_OTHERS: asChannelPermissionMask(1n << 34n),
|
||||
MOVE_OTHERS: asChannelPermissionMask(1n << 35n),
|
||||
DISCONNECT_OTHERS: asChannelPermissionMask(1n << 36n),
|
||||
MANAGE_VOICE_CHANNEL: asChannelPermissionMask(1n << 37n),
|
||||
} as const satisfies Record<string, ChannelPermissionMask>
|
||||
|
||||
export const SERVER_PERMISSION_DEFINITIONS: ServerPermissionDefinition[] = [
|
||||
{
|
||||
key: 'manage_server',
|
||||
label: 'Gérer le serveur',
|
||||
description: 'Modifier les paramètres généraux du serveur.',
|
||||
bit: SERVER_PERMISSIONS.MANAGE_SERVER,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'manage_roles',
|
||||
label: 'Gérer les rôles',
|
||||
description: 'Créer, modifier et supprimer des rôles.',
|
||||
bit: SERVER_PERMISSIONS.MANAGE_ROLES,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'manage_categories',
|
||||
label: 'Gérer les catégories',
|
||||
description: 'Créer, modifier et supprimer des catégories.',
|
||||
bit: SERVER_PERMISSIONS.MANAGE_CATEGORIES,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'manage_channels',
|
||||
label: 'Gérer les canaux',
|
||||
description: 'Créer, modifier et supprimer des canaux.',
|
||||
bit: SERVER_PERMISSIONS.MANAGE_CHANNELS,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'kick_members',
|
||||
label: 'Expulser des membres',
|
||||
description: 'Expulser un membre du serveur.',
|
||||
bit: SERVER_PERMISSIONS.KICK_MEMBERS,
|
||||
category: 'members',
|
||||
},
|
||||
{
|
||||
key: 'ban_members',
|
||||
label: 'Bannir des membres',
|
||||
description: 'Bannir un membre du serveur.',
|
||||
bit: SERVER_PERMISSIONS.BAN_MEMBERS,
|
||||
category: 'members',
|
||||
},
|
||||
{
|
||||
key: 'manage_members',
|
||||
label: 'Gérer les membres',
|
||||
description: 'Modifier le profil ou les rôles d’un membre.',
|
||||
bit: SERVER_PERMISSIONS.MANAGE_MEMBERS,
|
||||
category: 'members',
|
||||
},
|
||||
{
|
||||
key: 'view_members',
|
||||
label: 'Voir les membres',
|
||||
description: 'Voir la liste des membres du serveur.',
|
||||
bit: SERVER_PERMISSIONS.VIEW_MEMBERS,
|
||||
category: 'members',
|
||||
},
|
||||
]
|
||||
|
||||
export const CHANNEL_PERMISSION_DEFINITIONS: ChannelPermissionDefinition[] = [
|
||||
{
|
||||
key: 'read_channel',
|
||||
label: 'Lire le canal',
|
||||
description: 'Voir le canal et son contenu.',
|
||||
bit: CHANNEL_PERMISSIONS.READ_CHANNEL,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'send_message',
|
||||
label: 'Envoyer des messages',
|
||||
bit: CHANNEL_PERMISSIONS.SEND_MESSAGE,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'edit_own_message',
|
||||
label: 'Modifier ses messages',
|
||||
bit: CHANNEL_PERMISSIONS.EDIT_OWN_MESSAGE,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'delete_own_message',
|
||||
label: 'Supprimer ses messages',
|
||||
bit: CHANNEL_PERMISSIONS.DELETE_OWN_MESSAGE,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'edit_others_messages',
|
||||
label: 'Modifier les messages des autres',
|
||||
bit: CHANNEL_PERMISSIONS.EDIT_OTHERS_MESSAGES,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'delete_others_messages',
|
||||
label: 'Supprimer les messages des autres',
|
||||
bit: CHANNEL_PERMISSIONS.DELETE_OTHERS_MESSAGES,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'add_reactions',
|
||||
label: 'Ajouter des réactions',
|
||||
bit: CHANNEL_PERMISSIONS.ADD_REACTIONS,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'attach_files',
|
||||
label: 'Joindre des fichiers',
|
||||
bit: CHANNEL_PERMISSIONS.ATTACH_FILES,
|
||||
category: 'chat',
|
||||
},
|
||||
{
|
||||
key: 'manage_channel',
|
||||
label: 'Gérer le canal',
|
||||
description: 'Modifier les paramètres du canal.',
|
||||
bit: CHANNEL_PERMISSIONS.MANAGE_CHANNEL,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'manage_messages',
|
||||
label: 'Gérer les messages',
|
||||
bit: CHANNEL_PERMISSIONS.MANAGE_MESSAGES,
|
||||
category: 'management',
|
||||
},
|
||||
{
|
||||
key: 'join_voice',
|
||||
label: 'Rejoindre le vocal',
|
||||
bit: CHANNEL_PERMISSIONS.JOIN_VOICE,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'speak',
|
||||
label: 'Parler',
|
||||
bit: CHANNEL_PERMISSIONS.SPEAK,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'stream',
|
||||
label: 'Diffuser',
|
||||
bit: CHANNEL_PERMISSIONS.STREAM,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'mute_self',
|
||||
label: 'Se mettre en sourdine',
|
||||
bit: CHANNEL_PERMISSIONS.MUTE_SELF,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'mute_others',
|
||||
label: 'Rendre les autres muets',
|
||||
bit: CHANNEL_PERMISSIONS.MUTE_OTHERS,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'move_others',
|
||||
label: 'Déplacer les autres',
|
||||
bit: CHANNEL_PERMISSIONS.MOVE_OTHERS,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'disconnect_others',
|
||||
label: 'Déconnecter les autres',
|
||||
bit: CHANNEL_PERMISSIONS.DISCONNECT_OTHERS,
|
||||
category: 'voice',
|
||||
},
|
||||
{
|
||||
key: 'manage_voice_channel',
|
||||
label: 'Gérer le canal vocal',
|
||||
bit: CHANNEL_PERMISSIONS.MANAGE_VOICE_CHANNEL,
|
||||
category: 'management',
|
||||
},
|
||||
]
|
||||
|
||||
export function hasServerPermission(
|
||||
mask: ServerPermissionMask,
|
||||
required: ServerPermissionMask,
|
||||
): boolean {
|
||||
return (mask & required) === required
|
||||
}
|
||||
|
||||
export function grantServerPermission(
|
||||
mask: ServerPermissionMask,
|
||||
permission: ServerPermissionMask,
|
||||
): ServerPermissionMask {
|
||||
return asServerPermissionMask(mask | permission)
|
||||
}
|
||||
|
||||
export function revokeServerPermission(
|
||||
mask: ServerPermissionMask,
|
||||
permission: ServerPermissionMask,
|
||||
): ServerPermissionMask {
|
||||
return asServerPermissionMask(mask & ~permission)
|
||||
}
|
||||
|
||||
export function toggleServerPermission(
|
||||
mask: ServerPermissionMask,
|
||||
permission: ServerPermissionMask,
|
||||
enabled: boolean,
|
||||
): ServerPermissionMask {
|
||||
return enabled
|
||||
? grantServerPermission(mask, permission)
|
||||
: revokeServerPermission(mask, permission)
|
||||
}
|
||||
|
||||
export function hasChannelPermission(
|
||||
mask: ChannelPermissionMask,
|
||||
required: ChannelPermissionMask,
|
||||
): boolean {
|
||||
return (mask & required) === required
|
||||
}
|
||||
|
||||
export function grantChannelPermission(
|
||||
mask: ChannelPermissionMask,
|
||||
permission: ChannelPermissionMask,
|
||||
): ChannelPermissionMask {
|
||||
return asChannelPermissionMask(mask | permission)
|
||||
}
|
||||
|
||||
export function revokeChannelPermission(
|
||||
mask: ChannelPermissionMask,
|
||||
permission: ChannelPermissionMask,
|
||||
): ChannelPermissionMask {
|
||||
return asChannelPermissionMask(mask & ~permission)
|
||||
}
|
||||
|
||||
export function toggleChannelPermission(
|
||||
mask: ChannelPermissionMask,
|
||||
permission: ChannelPermissionMask,
|
||||
enabled: boolean,
|
||||
): ChannelPermissionMask {
|
||||
return enabled
|
||||
? grantChannelPermission(mask, permission)
|
||||
: revokeChannelPermission(mask, permission)
|
||||
}
|
||||
|
||||
export function permissionMaskToJson(
|
||||
mask: PermissionMaskInput,
|
||||
): number | string {
|
||||
const value = toBigInt(mask)
|
||||
|
||||
if (value < 0n) {
|
||||
throw new Error('Permission mask cannot be negative')
|
||||
}
|
||||
|
||||
return value <= BigInt(Number.MAX_SAFE_INTEGER)
|
||||
? Number(value)
|
||||
: value.toString()
|
||||
}
|
||||
|
||||
export function serverUserPermissionFromDto(
|
||||
dto: ServerUserPermissionDto,
|
||||
): ServerUserPermission {
|
||||
return {
|
||||
id: dto.id,
|
||||
server_id: dto.server_id,
|
||||
user_id: dto.user_id,
|
||||
permissions: toServerPermissionMask(dto.permissions),
|
||||
}
|
||||
}
|
||||
|
||||
export function serverRolePermissionFromDto(
|
||||
dto: ServerRolePermissionDto,
|
||||
): ServerRolePermission {
|
||||
return {
|
||||
id: dto.id,
|
||||
server_id: dto.server_id,
|
||||
role_id: dto.role_id,
|
||||
permissions: toServerPermissionMask(dto.permissions),
|
||||
}
|
||||
}
|
||||
|
||||
export function channelUserPermissionFromDto(
|
||||
dto: ChannelUserPermissionDto,
|
||||
): ChannelUserPermission {
|
||||
return {
|
||||
id: dto.id,
|
||||
channel_id: dto.channel_id,
|
||||
user_id: dto.user_id,
|
||||
permissions: toChannelPermissionMask(dto.permissions),
|
||||
}
|
||||
}
|
||||
|
||||
export function channelRolePermissionFromDto(
|
||||
dto: ChannelRolePermissionDto,
|
||||
): ChannelRolePermission {
|
||||
return {
|
||||
id: dto.id,
|
||||
channel_id: dto.channel_id,
|
||||
role_id: dto.role_id,
|
||||
permissions: toChannelPermissionMask(dto.permissions),
|
||||
}
|
||||
}
|
||||
@@ -495,11 +495,12 @@ impl MigrationTrait for Migration {
|
||||
.not_null()
|
||||
.default(0),
|
||||
)
|
||||
.primary_key(
|
||||
.index(
|
||||
Index::create()
|
||||
.name("pk_server_user_permission")
|
||||
.name("uq_server_user_permission")
|
||||
.col(Alias::new("server_id"))
|
||||
.col(Alias::new("user_id")),
|
||||
.col(Alias::new("user_id"))
|
||||
.unique(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
|
||||
Reference in New Issue
Block a user