This commit is contained in:
2026-08-02 13:11:11 +02:00
parent bb4e17ba2f
commit c10925b84b
5 changed files with 119 additions and 3 deletions
@@ -5,7 +5,7 @@ import {useServerStore} from '@/stores/server'
import {useRoleStore} from '@/stores/role'
import {useUserStore} from '@/stores/user'
import {usePermissions} from '@/composables/usePermissions'
import {toServerPermissionMask, type ServerPermissionMask} from '@/types/permissions'
import {toServerPermissionMask, type ServerPermissionMask, type ServerUserPermission} from '@/types/permissions'
import ServerPermissionEditor from '@/components/permissions/ServerPermissionEditor.vue'
const props = defineProps<{modelValue: boolean; serverId: string; serverName: string}>()
@@ -17,17 +17,21 @@ const permissionsApi = usePermissions()
const {roles} = storeToRefs(roleStore)
const activeTab = ref('general')
const selectedRoleId = ref<string | null>(null)
const selectedUserId = ref<string | null>(null)
const name = ref('')
const loading = ref(false)
const saving = ref(false)
const error = ref<string | null>(null)
const roleForm = ref('')
const rolePermissions = ref<ServerPermissionMask>(toServerPermissionMask(0))
const memberPermissions = ref<ServerPermissionMask>(toServerPermissionMask(0))
const userPermissions = ref<Record<string, ServerUserPermission>>({})
const selectedRole = computed(() => roles.value.find(role => role.id === selectedRoleId.value) || null)
const selectedMembers = computed(() => selectedRoleId.value ? roleStore.members[selectedRoleId.value] || [] : [])
const availableUsers = computed(() => userStore.users.filter(user => !selectedMembers.value.some(member => member.id === user.id)))
const memberToAdd = ref<string | null>(null)
const selectedUser = computed(() => userStore.users.find(user => user.id === selectedUserId.value) || null)
watch(() => props.modelValue, async open => {
if (open) await load()
@@ -44,13 +48,23 @@ watch(selectedRoleId, async roleId => {
if ((e as Error & {status?: number}).status !== 404) error.value = e instanceof Error ? e.message : 'Erreur de chargement'
}
})
watch(selectedUserId, userId => {
memberPermissions.value = userId && userPermissions.value[userId]
? userPermissions.value[userId].permissions
: toServerPermissionMask(0)
})
async function load() {
loading.value = true
error.value = null
name.value = props.serverName
try {
await Promise.all([roleStore.fetchRoles(props.serverId), userStore.fetchUsers(props.serverId)])
const [, , permissions] = await Promise.all([
roleStore.fetchRoles(props.serverId),
userStore.fetchUsers(props.serverId),
permissionsApi.listServerUserPermissions(props.serverId),
])
userPermissions.value = Object.fromEntries(permissions.map(permission => [permission.user_id, permission]))
} catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de chargement' }
finally { loading.value = false }
}
@@ -88,6 +102,25 @@ async function savePermissions(value: ServerPermissionMask) {
try { await permissionsApi.setServerRolePermission(props.serverId, selectedRoleId.value, value); rolePermissions.value = value }
catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de permissions' }
}
async function saveMemberPermissions(value: ServerPermissionMask) {
if (!selectedUserId.value) return
try {
const permission = await permissionsApi.setServerUserPermission(props.serverId, selectedUserId.value, value)
userPermissions.value[selectedUserId.value] = permission
memberPermissions.value = value
} catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de permissions' }
}
async function resetMemberPermissions() {
if (!selectedUserId.value) return
try {
await permissionsApi.removeServerUserPermission(props.serverId, selectedUserId.value)
delete userPermissions.value[selectedUserId.value]
memberPermissions.value = toServerPermissionMask(0)
} catch (e) {
const status = (e as Error & {status?: number}).status
if (status !== 404) error.value = e instanceof Error ? e.message : 'Erreur de réinitialisation'
}
}
</script>
<template>
@@ -101,6 +134,7 @@ async function savePermissions(value: ServerPermissionMask) {
<v-list density="compact" nav>
<v-list-item title="Général" prepend-icon="mdi-cog" :active="activeTab === 'general'" @click="activeTab = 'general'" />
<v-list-item title="Rôles" prepend-icon="mdi-shield-account" :active="activeTab === 'roles'" @click="activeTab = 'roles'" />
<v-list-item title="Membres" prepend-icon="mdi-account-cog" :active="activeTab === 'members'" @click="activeTab = 'members'" />
</v-list>
</v-col>
<v-col cols="12" md="9" class="pa-5">
@@ -110,7 +144,7 @@ async function savePermissions(value: ServerPermissionMask) {
<v-text-field v-model="name" label="Nom du serveur" :disabled="loading" />
<v-btn color="primary" :loading="saving" :disabled="!name.trim()" @click="saveServer">Enregistrer</v-btn>
</template>
<template v-else>
<template v-else-if="activeTab === 'roles'">
<div class="text-h6 mb-4">Rôles</div>
<v-row>
<v-col cols="12" md="4">
@@ -138,6 +172,42 @@ async function savePermissions(value: ServerPermissionMask) {
</v-col>
</v-row>
</template>
<template v-else>
<div class="text-h6 mb-4">Permissions des membres</div>
<v-row>
<v-col cols="12" md="4">
<v-list border density="compact" class="role-list">
<v-list-item
v-for="user in userStore.users"
:key="user.id"
:title="user.username"
:active="user.id === selectedUserId"
@click="selectedUserId = user.id"
>
<template #append>
<v-icon v-if="userPermissions[user.id]" icon="mdi-shield-check" size="small" />
</template>
</v-list-item>
</v-list>
</v-col>
<v-col cols="12" md="8">
<template v-if="selectedUser">
<v-chip class="mb-4" color="primary" size="small">{{ selectedUser.username }}</v-chip>
<ServerPermissionEditor
v-model="memberPermissions"
title="Permissions directes du membre"
@save="saveMemberPermissions"
/>
<v-btn class="mt-3" color="error" variant="text" @click="resetMemberPermissions">
Réinitialiser les permissions directes
</v-btn>
</template>
<v-sheet v-else class="empty-selection d-flex align-center justify-center text-medium-emphasis" border rounded>
Sélectionnez un membre.
</v-sheet>
</v-col>
</v-row>
</template>
</v-col>
</v-row>
</v-card-text>
@@ -56,6 +56,14 @@ export function usePermissions() {
return serverUserPermissionFromDto(dto)
}
async function listServerUserPermissions(
serverId: string,
): Promise<ServerUserPermission[]> {
const response = await api.get(`/servers/${serverId}/permissions/users`)
const dtos = await parseResponse<ServerUserPermissionDto[]>(response)
return dtos.map(serverUserPermissionFromDto)
}
async function setServerUserPermission(
serverId: string,
userId: string,
@@ -228,6 +236,7 @@ export function usePermissions() {
return {
getChannelPermissions,
getServerUserPermission,
listServerUserPermissions,
setServerUserPermission,
removeServerUserPermission,