Compare commits
2
Commits
9dbb7ffd5b
...
aa486be6e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa486be6e5 | ||
|
|
659fd0f304 |
@@ -0,0 +1,205 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import {computed, ref, watch} from 'vue'
|
||||||
|
import {useUserStore} from '@/stores/user'
|
||||||
|
import {useApi} from '@/composables/useApi'
|
||||||
|
import {usePermissions} from '@/composables/usePermissions'
|
||||||
|
import ChannelPermissionEditor from './ChannelPermissionEditor.vue'
|
||||||
|
import {toChannelPermissionMask, type ChannelPermissionMask, type ChannelPermissions} from '@/types/permissions'
|
||||||
|
|
||||||
|
interface Role { id: string; server_id: string; name: string; is_default: boolean }
|
||||||
|
interface Channel { id: string; name?: string | null }
|
||||||
|
type TargetType = 'role' | 'user'
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: boolean; channel: Channel | null; serverId: string }>()
|
||||||
|
const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
|
||||||
|
|
||||||
|
const users = useUserStore()
|
||||||
|
const api = useApi()
|
||||||
|
const permissionsApi = usePermissions()
|
||||||
|
const roles = ref<Role[]>([])
|
||||||
|
const configured = ref<ChannelPermissions>({users: [], roles: []})
|
||||||
|
const targetType = ref<TargetType>('role')
|
||||||
|
const targetId = ref<string | null>(null)
|
||||||
|
const addTargetId = ref<string | null>(null)
|
||||||
|
const mask = ref<ChannelPermissionMask>(toChannelPermissionMask(0))
|
||||||
|
const loading = ref(false)
|
||||||
|
const saving = ref(false)
|
||||||
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
|
const configuredEntries = computed(() => targetType.value === 'role' ? configured.value.roles : configured.value.users)
|
||||||
|
type PermissionEntry = ChannelPermissions['roles'][number] | ChannelPermissions['users'][number]
|
||||||
|
function entryTargetId(entry: PermissionEntry): string {
|
||||||
|
return 'role_id' in entry ? entry.role_id : entry.user_id
|
||||||
|
}
|
||||||
|
function entryName(entry: PermissionEntry): string {
|
||||||
|
const id = entryTargetId(entry)
|
||||||
|
return targetType.value === 'role'
|
||||||
|
? roles.value.find(role => role.id === id)?.name || id
|
||||||
|
: users.users.find(user => user.id === id)?.username || id
|
||||||
|
}
|
||||||
|
const availableTargets = computed(() => {
|
||||||
|
const used = new Set(configuredEntries.value.map(entryTargetId))
|
||||||
|
return targetType.value === 'role'
|
||||||
|
? roles.value.filter(role => !used.has(role.id))
|
||||||
|
: users.users.filter(user => !used.has(user.id))
|
||||||
|
})
|
||||||
|
const selectedName = computed(() => {
|
||||||
|
if (!targetId.value) return ''
|
||||||
|
if (targetType.value === 'role') return roles.value.find(role => role.id === targetId.value)?.name || targetId.value
|
||||||
|
return users.users.find(user => user.id === targetId.value)?.username || targetId.value
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, async open => {
|
||||||
|
if (open) await load()
|
||||||
|
else reset()
|
||||||
|
})
|
||||||
|
watch(targetType, () => { targetId.value = null; addTargetId.value = null; mask.value = toChannelPermissionMask(0); error.value = null })
|
||||||
|
watch(addTargetId, id => {
|
||||||
|
if (!id) return
|
||||||
|
targetId.value = id
|
||||||
|
mask.value = toChannelPermissionMask(0)
|
||||||
|
addTargetId.value = null
|
||||||
|
})
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
if (!props.channel) return
|
||||||
|
loading.value = true; error.value = null
|
||||||
|
try {
|
||||||
|
const [roleResponse] = await Promise.all([api.get('/groups'), users.fetchUsers(props.serverId)])
|
||||||
|
if (!roleResponse.ok) throw new Error('Impossible de charger les rôles')
|
||||||
|
roles.value = (await roleResponse.json() as Role[]).filter(role => role.server_id === props.serverId)
|
||||||
|
configured.value = await permissionsApi.getChannelPermissions(props.channel.id)
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e instanceof Error ? e.message : 'Erreur lors du chargement des permissions'
|
||||||
|
} finally { loading.value = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectExisting(id: string) {
|
||||||
|
targetId.value = id
|
||||||
|
const entry = configuredEntries.value.find(item => entryTargetId(item) === id)
|
||||||
|
mask.value = entry?.permissions ?? toChannelPermissionMask(0)
|
||||||
|
error.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save(value: ChannelPermissionMask) {
|
||||||
|
if (!props.channel || !targetId.value) return
|
||||||
|
saving.value = true; error.value = null
|
||||||
|
try {
|
||||||
|
if (targetType.value === 'role') await permissionsApi.setChannelRolePermission(props.channel.id, targetId.value, value)
|
||||||
|
else await permissionsApi.setChannelUserPermission(props.channel.id, targetId.value, value)
|
||||||
|
configured.value = await permissionsApi.getChannelPermissions(props.channel.id)
|
||||||
|
mask.value = value
|
||||||
|
} catch (e) { error.value = e instanceof Error ? e.message : 'Erreur lors de la sauvegarde' }
|
||||||
|
finally { saving.value = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resetPermission() {
|
||||||
|
if (!props.channel || !targetId.value) return
|
||||||
|
saving.value = true; error.value = null
|
||||||
|
try {
|
||||||
|
if (targetType.value === 'role') await permissionsApi.removeChannelRolePermission(props.channel.id, targetId.value)
|
||||||
|
else await permissionsApi.removeChannelUserPermission(props.channel.id, targetId.value)
|
||||||
|
configured.value = await permissionsApi.getChannelPermissions(props.channel.id)
|
||||||
|
targetId.value = null
|
||||||
|
mask.value = toChannelPermissionMask(0)
|
||||||
|
} catch (e) {
|
||||||
|
const status = e instanceof Error ? (e as Error & {status?: number}).status : undefined
|
||||||
|
if (status !== 404) error.value = e instanceof Error ? e.message : 'Erreur lors de la réinitialisation'
|
||||||
|
} finally { saving.value = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() { emit('update:modelValue', false) }
|
||||||
|
function reset() { configured.value = {users: [], roles: []}; targetId.value = null; addTargetId.value = null; mask.value = toChannelPermissionMask(0); error.value = null }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-dialog :model-value="modelValue" max-width="760" @update:model-value="emit('update:modelValue', $event)">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>Permissions — {{ channel?.name || 'Canal' }}</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-alert v-if="error" class="mb-4" type="error" density="compact">{{ error }}</v-alert>
|
||||||
|
<v-tabs v-model="targetType" class="mb-4">
|
||||||
|
<v-tab value="role">Rôles</v-tab>
|
||||||
|
<v-tab value="user">Membres</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
<v-row class="permission-layout" dense>
|
||||||
|
<v-col cols="12" md="4" class="permission-sidebar">
|
||||||
|
<div class="text-subtitle-2 mb-2">Cibles configurées</div>
|
||||||
|
<v-list v-if="!loading && configuredEntries.length" density="compact" lines="one" border class="permission-list">
|
||||||
|
<v-list-item
|
||||||
|
v-for="entry in configuredEntries"
|
||||||
|
:key="entry.id"
|
||||||
|
:active="targetId === entryTargetId(entry)"
|
||||||
|
@click="selectExisting(entryTargetId(entry))"
|
||||||
|
>
|
||||||
|
<v-list-item-title>{{ entryName(entry) }}</v-list-item-title>
|
||||||
|
<template #append><v-chip size="x-small" variant="tonal">{{ entry.permissions.toString(2).replace(/^0+/, '').length || 0 }}</v-chip></template>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
<div v-else-if="!loading" class="text-medium-emphasis text-body-2 py-4">Aucune permission directe configurée.</div>
|
||||||
|
<v-skeleton-loader v-else type="list-item-two-line" />
|
||||||
|
<v-select
|
||||||
|
v-model="addTargetId"
|
||||||
|
:items="availableTargets"
|
||||||
|
:item-title="targetType === 'role' ? 'name' : 'username'"
|
||||||
|
item-value="id"
|
||||||
|
:label="targetType === 'role' ? 'Ajouter un rôle' : 'Ajouter un membre'"
|
||||||
|
:loading="loading"
|
||||||
|
clearable
|
||||||
|
class="mt-3"
|
||||||
|
hide-details
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="8">
|
||||||
|
<div v-if="targetId" class="permission-editor">
|
||||||
|
<v-chip class="mb-3" color="primary" size="small">{{ selectedName }}</v-chip>
|
||||||
|
<ChannelPermissionEditor
|
||||||
|
v-model="mask"
|
||||||
|
:loading="saving"
|
||||||
|
title="Permissions du canal"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
|
<v-btn class="mt-3" color="error" variant="text" :loading="saving" @click="resetPermission">Réinitialiser les permissions directes</v-btn>
|
||||||
|
</div>
|
||||||
|
<v-sheet v-else class="empty-editor d-flex align-center justify-center text-center text-medium-emphasis" rounded border>
|
||||||
|
Sélectionnez une cible à gauche ou ajoutez-en une pour modifier ses permissions.
|
||||||
|
</v-sheet>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions><v-spacer/><v-btn variant="text" @click="close">Fermer</v-btn></v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.permission-layout {
|
||||||
|
min-height: 390px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-sidebar {
|
||||||
|
border-right: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-list {
|
||||||
|
max-height: 280px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-editor {
|
||||||
|
min-height: 360px;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 959px) {
|
||||||
|
.permission-sidebar {
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-editor {
|
||||||
|
min-height: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import {useApi} from '@/composables/useApi'
|
import {useApi} from '@/composables/useApi'
|
||||||
import {
|
import {
|
||||||
type ChannelRolePermission,
|
type ChannelRolePermission,
|
||||||
|
type ChannelPermissions,
|
||||||
|
type ChannelPermissionsDto,
|
||||||
|
channelPermissionsFromDto,
|
||||||
type ChannelRolePermissionDto,
|
type ChannelRolePermissionDto,
|
||||||
channelRolePermissionFromDto,
|
channelRolePermissionFromDto,
|
||||||
type ChannelUserPermission,
|
type ChannelUserPermission,
|
||||||
@@ -22,10 +25,11 @@ export function usePermissions() {
|
|||||||
async function parseResponse<T>(response: Response): Promise<T> {
|
async function parseResponse<T>(response: Response): Promise<T> {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const error = await response.json().catch(() => null)
|
const error = await response.json().catch(() => null)
|
||||||
|
const exception = new Error(
|
||||||
throw new Error(
|
|
||||||
error?.message || 'Erreur lors de la gestion des permissions',
|
error?.message || 'Erreur lors de la gestion des permissions',
|
||||||
)
|
) as Error & { status?: number }
|
||||||
|
exception.status = response.status
|
||||||
|
throw exception
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.status === 204) {
|
if (response.status === 204) {
|
||||||
@@ -129,6 +133,12 @@ export function usePermissions() {
|
|||||||
// Permissions canal - utilisateur
|
// Permissions canal - utilisateur
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function getChannelPermissions(channelId: string): Promise<ChannelPermissions> {
|
||||||
|
const response = await api.get(`/channels/${channelId}/permissions`)
|
||||||
|
const dto = await parseResponse<ChannelPermissionsDto>(response)
|
||||||
|
return channelPermissionsFromDto(dto)
|
||||||
|
}
|
||||||
|
|
||||||
async function getChannelUserPermission(
|
async function getChannelUserPermission(
|
||||||
channelId: string,
|
channelId: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
@@ -216,6 +226,7 @@ export function usePermissions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
getChannelPermissions,
|
||||||
getServerUserPermission,
|
getServerUserPermission,
|
||||||
setServerUserPermission,
|
setServerUserPermission,
|
||||||
removeServerUserPermission,
|
removeServerUserPermission,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import CreateCategoryDialog from '@/components/category/CreateCategoryDialog.vue
|
|||||||
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
|
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
|
||||||
import {useUserStore} from "@/stores/user.ts";
|
import {useUserStore} from "@/stores/user.ts";
|
||||||
import {useServerStore} from "@/stores/server.ts";
|
import {useServerStore} from "@/stores/server.ts";
|
||||||
|
import ChannelPermissionsDialog from '@/components/permissions/ChannelPermissionsDialog.vue'
|
||||||
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
serverId: string
|
serverId: string
|
||||||
@@ -22,6 +24,9 @@ const userStore = useUserStore()
|
|||||||
const serverStore = useServerStore()
|
const serverStore = useServerStore()
|
||||||
const {currentTree} = storeToRefs(serverStore)
|
const {currentTree} = storeToRefs(serverStore)
|
||||||
const {openContextMenu} = useContextMenu()
|
const {openContextMenu} = useContextMenu()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const showPermissionsDialog = ref(false)
|
||||||
|
const selectedChannel = ref<any | null>(null)
|
||||||
|
|
||||||
|
|
||||||
const loadServerData = async (targetServerId: string) => {
|
const loadServerData = async (targetServerId: string) => {
|
||||||
@@ -111,6 +116,14 @@ async function deleteChannel(channelId: string) {
|
|||||||
|
|
||||||
function onChannelContextMenu(event: MouseEvent, channel: any) {
|
function onChannelContextMenu(event: MouseEvent, channel: any) {
|
||||||
const menuItems: MenuItem[] = [
|
const menuItems: MenuItem[] = [
|
||||||
|
...(authStore.isAdmin ? [{
|
||||||
|
label: 'Gérer les permissions',
|
||||||
|
icon: 'mdi-shield-key',
|
||||||
|
action: () => {
|
||||||
|
selectedChannel.value = channel
|
||||||
|
showPermissionsDialog.value = true
|
||||||
|
},
|
||||||
|
}] : []),
|
||||||
{
|
{
|
||||||
label: 'Marquer comme lu',
|
label: 'Marquer comme lu',
|
||||||
icon: 'mdi-check',
|
icon: 'mdi-check',
|
||||||
@@ -194,6 +207,12 @@ function onChannelContextMenu(event: MouseEvent, channel: any) {
|
|||||||
@created="refreshServerTree"
|
@created="refreshServerTree"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ChannelPermissionsDialog
|
||||||
|
v-model="showPermissionsDialog"
|
||||||
|
:channel="selectedChannel"
|
||||||
|
:server-id="serverId"
|
||||||
|
/>
|
||||||
|
|
||||||
<v-main>
|
<v-main>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ export interface ChannelRolePermission {
|
|||||||
permissions: ChannelPermissionMask
|
permissions: ChannelPermissionMask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChannelPermissions {
|
||||||
|
users: ChannelUserPermission[]
|
||||||
|
roles: ChannelRolePermission[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface ServerUserPermissionDto {
|
export interface ServerUserPermissionDto {
|
||||||
id: string
|
id: string
|
||||||
server_id: string
|
server_id: string
|
||||||
@@ -80,6 +85,11 @@ export interface ChannelRolePermissionDto {
|
|||||||
permissions: number | string
|
permissions: number | string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChannelPermissionsDto {
|
||||||
|
users: ChannelUserPermissionDto[]
|
||||||
|
roles: ChannelRolePermissionDto[]
|
||||||
|
}
|
||||||
|
|
||||||
function asServerPermissionMask(value: bigint): ServerPermissionMask {
|
function asServerPermissionMask(value: bigint): ServerPermissionMask {
|
||||||
return value as ServerPermissionMask
|
return value as ServerPermissionMask
|
||||||
}
|
}
|
||||||
@@ -443,3 +453,12 @@ export function channelRolePermissionFromDto(
|
|||||||
permissions: toChannelPermissionMask(dto.permissions),
|
permissions: toChannelPermissionMask(dto.permissions),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function channelPermissionsFromDto(
|
||||||
|
dto: ChannelPermissionsDto,
|
||||||
|
): ChannelPermissions {
|
||||||
|
return {
|
||||||
|
users: dto.users.map(channelUserPermissionFromDto),
|
||||||
|
roles: dto.roles.map(channelRolePermissionFromDto),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,3 +70,9 @@ pub struct ChannelRolePermissionResponse {
|
|||||||
pub role_id: Uuid,
|
pub role_id: Uuid,
|
||||||
pub permissions: u64,
|
pub permissions: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, ToSchema)]
|
||||||
|
pub struct ChannelPermissionsResponse {
|
||||||
|
pub users: Vec<ChannelUserPermissionResponse>,
|
||||||
|
pub roles: Vec<ChannelRolePermissionResponse>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,6 +59,16 @@ impl ChannelRepository {
|
|||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_user_permissions(
|
||||||
|
&self,
|
||||||
|
channel_id: Uuid,
|
||||||
|
) -> AnyResult<Vec<channel_user_permission::Model>> {
|
||||||
|
Ok(channel_user_permission::Entity::find()
|
||||||
|
.filter(channel_user_permission::Column::ChannelId.eq(channel_id))
|
||||||
|
.all(&self.context.db)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_user_permission(
|
pub async fn set_user_permission(
|
||||||
&self,
|
&self,
|
||||||
channel_id: Uuid,
|
channel_id: Uuid,
|
||||||
@@ -109,6 +119,16 @@ impl ChannelRepository {
|
|||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_role_permissions(
|
||||||
|
&self,
|
||||||
|
channel_id: Uuid,
|
||||||
|
) -> AnyResult<Vec<channel_role_permission::Model>> {
|
||||||
|
Ok(channel_role_permission::Entity::find()
|
||||||
|
.filter(channel_role_permission::Column::ChannelId.eq(channel_id))
|
||||||
|
.all(&self.context.db)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_role_permission(
|
pub async fn set_role_permission(
|
||||||
&self,
|
&self,
|
||||||
channel_id: Uuid,
|
channel_id: Uuid,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::core::state::AppState;
|
|||||||
use crate::http::context::Superuser;
|
use crate::http::context::Superuser;
|
||||||
use crate::http::error::HTTPError;
|
use crate::http::error::HTTPError;
|
||||||
use crate::domain::dto::channel::{
|
use crate::domain::dto::channel::{
|
||||||
ChannelQueryParams, ChannelResponse, ChannelRolePermissionResponse,
|
ChannelQueryParams, ChannelResponse, ChannelPermissionsResponse, ChannelRolePermissionResponse,
|
||||||
ChannelUserPermissionResponse, CreateChannelRequest, SetChannelPermissionRequest,
|
ChannelUserPermissionResponse, CreateChannelRequest, SetChannelPermissionRequest,
|
||||||
UpdateChannelRequest,
|
UpdateChannelRequest,
|
||||||
};
|
};
|
||||||
@@ -69,6 +69,26 @@ pub async fn get_by_id(
|
|||||||
Ok(Json(mapper::channel_model_to_channel_response(channel)))
|
Ok(Json(mapper::channel_model_to_channel_response(channel)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Liste les permissions directes configurées pour un canal.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/channels/{channel_id}/permissions",
|
||||||
|
params(("channel_id" = Uuid, Path, description = "ID du canal")),
|
||||||
|
responses((status = 200, body = ChannelPermissionsResponse), (status = 404, description = "Canal non trouvé")),
|
||||||
|
tag = "Channel Permissions"
|
||||||
|
)]
|
||||||
|
pub async fn list_permissions(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Path(channel_id): Path<Uuid>,
|
||||||
|
) -> Result<Json<ChannelPermissionsResponse>, HTTPError> {
|
||||||
|
state.repositories.channel.get_by_id(channel_id).await?.ok_or(HTTPError::NotFound)?;
|
||||||
|
let (users, roles) = tokio::try_join!(
|
||||||
|
state.repositories.channel.list_user_permissions(channel_id),
|
||||||
|
state.repositories.channel.list_role_permissions(channel_id),
|
||||||
|
)?;
|
||||||
|
Ok(Json(mapper::channel_permissions_to_response(users, roles)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Crée un nouveau channel
|
/// Crée un nouveau channel
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::domain::dto::channel::{
|
use crate::domain::dto::channel::{
|
||||||
ChannelQueryParams, ChannelResponse, ChannelRolePermissionResponse,
|
ChannelPermissionsResponse, ChannelQueryParams, ChannelResponse, ChannelRolePermissionResponse,
|
||||||
ChannelUserPermissionResponse, CreateChannelRequest, UpdateChannelRequest,
|
ChannelUserPermissionResponse, CreateChannelRequest, UpdateChannelRequest,
|
||||||
};
|
};
|
||||||
use crate::models::{channel, channel_role_permission, channel_user_permission};
|
use crate::models::{channel, channel_role_permission, channel_user_permission};
|
||||||
@@ -71,6 +71,16 @@ pub fn channel_role_permission_to_response(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn channel_permissions_to_response(
|
||||||
|
users: Vec<channel_user_permission::Model>,
|
||||||
|
roles: Vec<channel_role_permission::Model>,
|
||||||
|
) -> ChannelPermissionsResponse {
|
||||||
|
ChannelPermissionsResponse {
|
||||||
|
users: users.into_iter().map(channel_user_permission_to_response).collect(),
|
||||||
|
roles: roles.into_iter().map(channel_role_permission_to_response).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn query_params_to_channel_filter(params: ChannelQueryParams) -> ChannelFilter {
|
pub fn query_params_to_channel_filter(params: ChannelQueryParams) -> ChannelFilter {
|
||||||
ChannelFilter {
|
ChannelFilter {
|
||||||
server_id: params.server_id,
|
server_id: params.server_id,
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ pub fn router() -> Router<AppState> {
|
|||||||
.put(handlers::update)
|
.put(handlers::update)
|
||||||
.delete(handlers::delete),
|
.delete(handlers::delete),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/channels/{channel_id}/permissions",
|
||||||
|
get(handlers::list_permissions),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/channels/{channel_id}/permissions/users/{user_id}",
|
"/channels/{channel_id}/permissions/users/{user_id}",
|
||||||
get(handlers::get_user_permission)
|
get(handlers::get_user_permission)
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ use crate::core::state::AppState;
|
|||||||
use crate::http::context::Superuser;
|
use crate::http::context::Superuser;
|
||||||
use crate::http::error::HTTPError;
|
use crate::http::error::HTTPError;
|
||||||
use crate::domain::dto::user::{CreateUserRequest, UpdateUserRequest, UserResponse};
|
use crate::domain::dto::user::{CreateUserRequest, UpdateUserRequest, UserResponse};
|
||||||
|
use crate::domain::dto::user::UserQueryParams;
|
||||||
use crate::routes::user::mapper;
|
use crate::routes::user::mapper;
|
||||||
use axum::{
|
use axum::{
|
||||||
Json,
|
Json,
|
||||||
extract::{Path, State},
|
extract::{Path, Query, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -28,8 +29,11 @@ use uuid::Uuid;
|
|||||||
pub async fn get_all(
|
pub async fn get_all(
|
||||||
_admin: Superuser,
|
_admin: Superuser,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
|
Query(filters): Query<UserQueryParams>,
|
||||||
) -> Result<Json<Vec<UserResponse>>, HTTPError> {
|
) -> Result<Json<Vec<UserResponse>>, HTTPError> {
|
||||||
let users = state.repositories.user.get_all().await?;
|
let users = state.repositories.user.filter(crate::repositories::types::UserFilter {
|
||||||
|
server_id: filters.server_id,
|
||||||
|
}).await?;
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
users
|
users
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
Reference in New Issue
Block a user