This commit is contained in:
2026-07-30 19:34:39 +02:00
parent 1bb00e1edf
commit 086e5ab0ea
7 changed files with 71 additions and 4 deletions
+3 -1
View File
@@ -4,6 +4,7 @@ import {computed, nextTick, onMounted, ref, watch} from 'vue';
import {useRoute} from 'vue-router'; import {useRoute} from 'vue-router';
import {storeToRefs} from 'pinia'; import {storeToRefs} from 'pinia';
import {useMessageStore} from '@/stores/message'; import {useMessageStore} from '@/stores/message';
import {useUserStore} from "@/stores/user.ts";
const props = defineProps<{ const props = defineProps<{
serverId: string serverId: string
@@ -14,6 +15,7 @@ const channelId = computed(() => props.channelId);
const route = useRoute(); const route = useRoute();
const messageStore = useMessageStore(); const messageStore = useMessageStore();
const userStore = useUserStore();
// Référence vers l'élément scrollable // Référence vers l'élément scrollable
const messageContainer = ref<HTMLElement | null>(null); const messageContainer = ref<HTMLElement | null>(null);
@@ -94,7 +96,7 @@ watch(messages, () => {
</template> </template>
<v-list-item-title class="d-flex align-center"> <v-list-item-title class="d-flex align-center">
<span class="font-weight-bold text-subtitle-1 mr-2">{{ msg.user_id }}</span> <span class="font-weight-bold text-subtitle-1 mr-2">{{ userStore.usersById[msg.user_id]?.username }}</span>
<span class="text-caption text-grey">{{ msg.created_at }}</span> <span class="text-caption text-grey">{{ msg.created_at }}</span>
</v-list-item-title> </v-list-item-title>
+5 -1
View File
@@ -6,6 +6,7 @@ import {ref, watch} from 'vue'
import {useRoute} from 'vue-router' import {useRoute} from 'vue-router'
import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue' import CreateChannelDialog from '@/components/channel/CreateChannelDialog.vue'
import {type MenuItem, useContextMenu} from '@/composables/useContextMenu' import {type MenuItem, useContextMenu} from '@/composables/useContextMenu'
import {useUserStore} from "@/stores/user.ts";
const props = defineProps<{ const props = defineProps<{
serverId: string serverId: string
@@ -15,6 +16,7 @@ const props = defineProps<{
const route = useRoute() const route = useRoute()
const channelStore = useChannelStore() const channelStore = useChannelStore()
const categoryStore = useCategoryStore() const categoryStore = useCategoryStore()
const userStore = useUserStore()
const {channels} = storeToRefs(channelStore) const {channels} = storeToRefs(channelStore)
const {categories} = storeToRefs(categoryStore) const {categories} = storeToRefs(categoryStore)
const {openContextMenu} = useContextMenu() const {openContextMenu} = useContextMenu()
@@ -24,10 +26,12 @@ const loadServerData = async (targetServerId: string) => {
if (!targetServerId) return if (!targetServerId) return
channelStore.reset() channelStore.reset()
categoryStore.reset() categoryStore.reset()
userStore.reset()
try { try {
await Promise.all([ await Promise.all([
channelStore.fetchChannels(targetServerId), channelStore.fetchChannels(targetServerId),
categoryStore.fetchCategories(targetServerId) categoryStore.fetchCategories(targetServerId),
userStore.fetchUsers(targetServerId)
]) ])
} catch (error) { } catch (error) {
console.error('Failed to load server-scoped channels and categories:', error) console.error('Failed to load server-scoped channels and categories:', error)
+31
View File
@@ -0,0 +1,31 @@
import {defineStore} from 'pinia'
import {useApi} from "@/composables/useApi.ts";
import type {User} from "@/types/user";
export const useUserStore = defineStore('user', {
state: () => ({
users: [] as User[]
}),
getters: {
usersById: (state): Record<string, User> => {
return state.users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {} as Record<string, User>);
}
},
actions: {
async fetchUsers(serverId?: string) {
let api = useApi();
let url = "/users";
if (serverId) {
url += `?server_id=${serverId}`;
}
const response = await api.get(url);
this.users = await response.json();
},
reset() {
this.users = [];
}
}
});
+8
View File
@@ -0,0 +1,8 @@
export interface User {
id: string
username: string
pub_key: string | null
is_superuser: boolean
created_at: string
updated_at: string
}
+5
View File
@@ -3,6 +3,11 @@ use serde::{Deserialize, Serialize};
use utoipa::ToSchema; use utoipa::ToSchema;
use uuid::Uuid; use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, ToSchema, utoipa::IntoParams)]
pub struct UserQueryParams {
pub server_id: Option<Uuid>,
}
#[derive(Debug, Serialize, Deserialize, ToSchema)] #[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct CreateUserRequest { pub struct CreateUserRequest {
pub username: String, pub username: String,
+4
View File
@@ -28,3 +28,7 @@ pub struct MessageFilter {
pub struct ChannelFilter { pub struct ChannelFilter {
pub server_id: Option<uuid::Uuid>, pub server_id: Option<uuid::Uuid>,
} }
pub struct UserFilter {
pub server_id: Option<uuid::Uuid>,
}
+15 -2
View File
@@ -1,8 +1,10 @@
use crate::auth::password; use crate::auth::password;
use crate::models::user; use crate::models::{server_user, user};
use crate::repositories::types::UserFilter;
use crate::repositories::{AnyResult, RepositoryContext}; use crate::repositories::{AnyResult, RepositoryContext};
use sea_orm::{ use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, PaginatorTrait, QueryFilter, Set, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, JoinType, PaginatorTrait,
QueryFilter, QuerySelect, RelationTrait, Set,
}; };
use std::sync::Arc; use std::sync::Arc;
@@ -16,6 +18,17 @@ impl UserRepository {
Ok(user::Entity::find().all(&self.context.db).await?) Ok(user::Entity::find().all(&self.context.db).await?)
} }
pub async fn filter(&self, filter: UserFilter) -> AnyResult<Vec<user::Model>> {
let mut query = user::Entity::find();
if let Some(s_id) = filter.server_id {
query = query
.join(JoinType::InnerJoin, user::Relation::ServerUser.def())
.filter(server_user::Column::ServerId.eq(s_id))
.distinct();
}
Ok(query.all(&self.context.db).await?)
}
pub async fn count(&self) -> AnyResult<u64> { pub async fn count(&self) -> AnyResult<u64> {
Ok(user::Entity::find().count(&self.context.db).await?) Ok(user::Entity::find().count(&self.context.db).await?)
} }