init
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export interface User {
|
||||||
|
id: string
|
||||||
|
username: string
|
||||||
|
pub_key: string | null
|
||||||
|
is_superuser: boolean
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -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?)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user