init
This commit is contained in:
@@ -5,7 +5,7 @@ import {useServerStore} from '@/stores/server'
|
|||||||
import {useRoleStore} from '@/stores/role'
|
import {useRoleStore} from '@/stores/role'
|
||||||
import {useUserStore} from '@/stores/user'
|
import {useUserStore} from '@/stores/user'
|
||||||
import {usePermissions} from '@/composables/usePermissions'
|
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'
|
import ServerPermissionEditor from '@/components/permissions/ServerPermissionEditor.vue'
|
||||||
|
|
||||||
const props = defineProps<{modelValue: boolean; serverId: string; serverName: string}>()
|
const props = defineProps<{modelValue: boolean; serverId: string; serverName: string}>()
|
||||||
@@ -17,17 +17,21 @@ const permissionsApi = usePermissions()
|
|||||||
const {roles} = storeToRefs(roleStore)
|
const {roles} = storeToRefs(roleStore)
|
||||||
const activeTab = ref('general')
|
const activeTab = ref('general')
|
||||||
const selectedRoleId = ref<string | null>(null)
|
const selectedRoleId = ref<string | null>(null)
|
||||||
|
const selectedUserId = ref<string | null>(null)
|
||||||
const name = ref('')
|
const name = ref('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
const roleForm = ref('')
|
const roleForm = ref('')
|
||||||
const rolePermissions = ref<ServerPermissionMask>(toServerPermissionMask(0))
|
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 selectedRole = computed(() => roles.value.find(role => role.id === selectedRoleId.value) || null)
|
||||||
const selectedMembers = computed(() => selectedRoleId.value ? roleStore.members[selectedRoleId.value] || [] : [])
|
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 availableUsers = computed(() => userStore.users.filter(user => !selectedMembers.value.some(member => member.id === user.id)))
|
||||||
const memberToAdd = ref<string | null>(null)
|
const memberToAdd = ref<string | null>(null)
|
||||||
|
const selectedUser = computed(() => userStore.users.find(user => user.id === selectedUserId.value) || null)
|
||||||
|
|
||||||
watch(() => props.modelValue, async open => {
|
watch(() => props.modelValue, async open => {
|
||||||
if (open) await load()
|
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'
|
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() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
error.value = null
|
error.value = null
|
||||||
name.value = props.serverName
|
name.value = props.serverName
|
||||||
try {
|
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' }
|
} catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de chargement' }
|
||||||
finally { loading.value = false }
|
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 }
|
try { await permissionsApi.setServerRolePermission(props.serverId, selectedRoleId.value, value); rolePermissions.value = value }
|
||||||
catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de permissions' }
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -101,6 +134,7 @@ async function savePermissions(value: ServerPermissionMask) {
|
|||||||
<v-list density="compact" nav>
|
<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="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="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-list>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="9" class="pa-5">
|
<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-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>
|
<v-btn color="primary" :loading="saving" :disabled="!name.trim()" @click="saveServer">Enregistrer</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else-if="activeTab === 'roles'">
|
||||||
<div class="text-h6 mb-4">Rôles</div>
|
<div class="text-h6 mb-4">Rôles</div>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="4">
|
<v-col cols="12" md="4">
|
||||||
@@ -138,6 +172,42 @@ async function savePermissions(value: ServerPermissionMask) {
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</template>
|
</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-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ export function usePermissions() {
|
|||||||
return serverUserPermissionFromDto(dto)
|
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(
|
async function setServerUserPermission(
|
||||||
serverId: string,
|
serverId: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
@@ -228,6 +236,7 @@ export function usePermissions() {
|
|||||||
return {
|
return {
|
||||||
getChannelPermissions,
|
getChannelPermissions,
|
||||||
getServerUserPermission,
|
getServerUserPermission,
|
||||||
|
listServerUserPermissions,
|
||||||
setServerUserPermission,
|
setServerUserPermission,
|
||||||
removeServerUserPermission,
|
removeServerUserPermission,
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,16 @@ impl ServerRepository {
|
|||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_user_permissions(
|
||||||
|
&self,
|
||||||
|
server_id: Uuid,
|
||||||
|
) -> AnyResult<Vec<server_user_permission::Model>> {
|
||||||
|
Ok(server_user_permission::Entity::find()
|
||||||
|
.filter(server_user_permission::Column::ServerId.eq(server_id))
|
||||||
|
.all(&self.context.db)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_user_permission(
|
pub async fn set_user_permission(
|
||||||
&self,
|
&self,
|
||||||
server_id: Uuid,
|
server_id: Uuid,
|
||||||
|
|||||||
@@ -216,6 +216,23 @@ pub async fn get_user_permission(
|
|||||||
Ok(Json(mapper::server_user_permission_to_response(permission)))
|
Ok(Json(mapper::server_user_permission_to_response(permission)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Liste les permissions directes des utilisateurs d'un serveur.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/servers/{server_id}/permissions/users",
|
||||||
|
params(("server_id" = Uuid, Path, description = "ID du serveur")),
|
||||||
|
responses((status = 200, body = [ServerUserPermissionResponse])),
|
||||||
|
tag = "Server Permissions"
|
||||||
|
)]
|
||||||
|
pub async fn list_user_permissions(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Path(server_id): Path<Uuid>,
|
||||||
|
) -> Result<Json<Vec<ServerUserPermissionResponse>>, HTTPError> {
|
||||||
|
state.repositories.server.get_by_id(server_id).await?.ok_or(HTTPError::NotFound)?;
|
||||||
|
let permissions = state.repositories.server.get_user_permissions(server_id).await?;
|
||||||
|
Ok(Json(permissions.into_iter().map(mapper::server_user_permission_to_response).collect()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Définit ou remplace les permissions directes d'un utilisateur sur un serveur.
|
/// Définit ou remplace les permissions directes d'un utilisateur sur un serveur.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
put,
|
put,
|
||||||
@@ -232,10 +249,14 @@ pub async fn get_user_permission(
|
|||||||
tag = "Server Permissions"
|
tag = "Server Permissions"
|
||||||
)]
|
)]
|
||||||
pub async fn set_user_permission(
|
pub async fn set_user_permission(
|
||||||
|
user: CurrentUser,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path((server_id, user_id)): Path<(Uuid, Uuid)>,
|
Path((server_id, user_id)): Path<(Uuid, Uuid)>,
|
||||||
Json(payload): Json<SetServerPermissionRequest>,
|
Json(payload): Json<SetServerPermissionRequest>,
|
||||||
) -> Result<Json<ServerUserPermissionResponse>, HTTPError> {
|
) -> Result<Json<ServerUserPermissionResponse>, HTTPError> {
|
||||||
|
require_server_permission(&state, &user, server_id, ServerPermission::MANAGE_MEMBERS).await?;
|
||||||
|
state.repositories.server.get_user(server_id, user_id).await?
|
||||||
|
.ok_or(HTTPError::BadRequest("User is not a member of this server".to_string()))?;
|
||||||
state
|
state
|
||||||
.repositories
|
.repositories
|
||||||
.server
|
.server
|
||||||
@@ -268,9 +289,11 @@ pub async fn set_user_permission(
|
|||||||
tag = "Server Permissions"
|
tag = "Server Permissions"
|
||||||
)]
|
)]
|
||||||
pub async fn remove_user_permission(
|
pub async fn remove_user_permission(
|
||||||
|
user: CurrentUser,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path((server_id, user_id)): Path<(Uuid, Uuid)>,
|
Path((server_id, user_id)): Path<(Uuid, Uuid)>,
|
||||||
) -> Result<StatusCode, HTTPError> {
|
) -> Result<StatusCode, HTTPError> {
|
||||||
|
require_server_permission(&state, &user, server_id, ServerPermission::MANAGE_MEMBERS).await?;
|
||||||
if state
|
if state
|
||||||
.repositories
|
.repositories
|
||||||
.server
|
.server
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ pub fn router() -> Router<AppState> {
|
|||||||
.delete(handlers::delete),
|
.delete(handlers::delete),
|
||||||
)
|
)
|
||||||
.route("/servers/{server_id}/tree", get(handlers::get_tree))
|
.route("/servers/{server_id}/tree", get(handlers::get_tree))
|
||||||
|
.route(
|
||||||
|
"/servers/{server_id}/permissions/users",
|
||||||
|
get(handlers::list_user_permissions),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/servers/{server_id}/permissions/users/{user_id}",
|
"/servers/{server_id}/permissions/users/{user_id}",
|
||||||
get(handlers::get_user_permission)
|
get(handlers::get_user_permission)
|
||||||
|
|||||||
Reference in New Issue
Block a user