From 7a593fc2046baa9074ed4015aaa9527e78584ac7 Mon Sep 17 00:00:00 2001 From: Nell Date: Sun, 28 Jun 2026 18:12:00 +0200 Subject: [PATCH] Init --- Cargo.lock | 35 +++++++ Cargo.toml | 2 + frontend/src/App.vue | 8 +- frontend/src/composables/useApi.ts | 9 +- frontend/src/layouts/AdminLayout.vue | 32 +++++++ frontend/src/layouts/AppLayout.vue | 65 +++++++++++++ frontend/src/layouts/AuthLayout.vue | 16 ++++ frontend/src/pages/{ => auth}/join.vue | 2 +- frontend/src/pages/{ => auth}/login.vue | 2 +- frontend/src/router/index.ts | 81 ++++++++++------ frontend/src/stores/app.ts | 5 +- frontend/src/stores/auth.ts | 94 ++++++++++++++----- frontend/src/stores/category.ts | 2 +- frontend/src/stores/channel.ts | 2 +- frontend/src/stores/gateway.ts | 20 ++-- frontend/src/stores/server.ts | 2 +- frontend/vite.config.mts | 16 +++- .../src/m20220101_000001_create_table.rs | 10 ++ src/auth/token.rs | 2 - src/http/middleware.rs | 6 ++ src/models/channel.rs | 3 +- src/routes/auth/handlers.rs | 71 +++++++++++++- src/routes/auth/routes.rs | 3 +- src/routes/channel/dto.rs | 9 +- src/routes/channel/mapper.rs | 9 +- src/routes/gateway/handlers.rs | 3 +- src/routes/openapi.rs | 4 +- 27 files changed, 413 insertions(+), 100 deletions(-) create mode 100644 frontend/src/layouts/AdminLayout.vue create mode 100644 frontend/src/layouts/AppLayout.vue create mode 100644 frontend/src/layouts/AuthLayout.vue rename frontend/src/pages/{ => auth}/join.vue (97%) rename frontend/src/pages/{ => auth}/login.vue (96%) diff --git a/Cargo.lock b/Cargo.lock index 149be3d..f134bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -583,6 +583,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-extra" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" +dependencies = [ + "axum", + "axum-core", + "bytes", + "cookie", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "base64" version = "0.22.1" @@ -935,6 +957,17 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -2346,6 +2379,7 @@ dependencies = [ "argon2", "async-trait", "axum", + "axum-extra", "bitflags", "chrono", "config", @@ -2360,6 +2394,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "time", "tokio", "toml", "tower", diff --git a/Cargo.toml b/Cargo.toml index 4e09dc0..e7a2253 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [".", "migration", "event_bus"] [dependencies] tokio = { version = "1.52.3", features = ["full"] } axum = { version = "0.8", features = ["ws"] } +axum-extra = { version = "0.12.6", features = ["cookie"] } config = "0.15.24" sea-orm = { version = "2.0.0-rc.41", features = ["sqlx-sqlite", "sqlx-postgres", "sqlx-mysql", "runtime-tokio", "with-chrono", "with-uuid", "with-json", "schema-sync"] } migration = { path = "migration" } @@ -39,3 +40,4 @@ async-trait = "0.1.89" anyhow = "1.0.102" futures-util = "0.3" form_urlencoded = "1.2.2" +time = "0.3.47" diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6ceb9da..510535f 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,11 +1,7 @@ diff --git a/frontend/src/composables/useApi.ts b/frontend/src/composables/useApi.ts index 3645976..8eaebc9 100644 --- a/frontend/src/composables/useApi.ts +++ b/frontend/src/composables/useApi.ts @@ -4,7 +4,8 @@ import {useAuthStore} from "@/stores/auth"; export function useApi() { const appStore = useAppStore() const authStore = useAuthStore() - const baseUrl = `${appStore.baseurl}/api` + // const baseUrl = `${appStore.baseurl}/api` + const baseUrl = '/api' const request = async (endpoint: string, options: RequestInit = {}) => { const headers = new Headers(options.headers) @@ -13,9 +14,9 @@ export function useApi() { headers.set('Content-Type', 'application/json') } - if (authStore.token) { - headers.set('Authorization', `Bearer ${authStore.token}`) - } + // if (authStore.token) { + // headers.set('Authorization', `Bearer ${authStore.token}`) + // } const config = { ...options, diff --git a/frontend/src/layouts/AdminLayout.vue b/frontend/src/layouts/AdminLayout.vue new file mode 100644 index 0000000..86c3fa5 --- /dev/null +++ b/frontend/src/layouts/AdminLayout.vue @@ -0,0 +1,32 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/layouts/AppLayout.vue b/frontend/src/layouts/AppLayout.vue new file mode 100644 index 0000000..3b1d5c3 --- /dev/null +++ b/frontend/src/layouts/AppLayout.vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/layouts/AuthLayout.vue b/frontend/src/layouts/AuthLayout.vue new file mode 100644 index 0000000..d17c050 --- /dev/null +++ b/frontend/src/layouts/AuthLayout.vue @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/pages/join.vue b/frontend/src/pages/auth/join.vue similarity index 97% rename from frontend/src/pages/join.vue rename to frontend/src/pages/auth/join.vue index 7b3cea7..e3d1e68 100644 --- a/frontend/src/pages/join.vue +++ b/frontend/src/pages/auth/join.vue @@ -137,7 +137,7 @@ async function handleRegister() {
- Déjà un compte ? Connectez-vous + Déjà un compte ? Connectez-vous
diff --git a/frontend/src/pages/login.vue b/frontend/src/pages/auth/login.vue similarity index 96% rename from frontend/src/pages/login.vue rename to frontend/src/pages/auth/login.vue index 9eb6aee..cb997ab 100644 --- a/frontend/src/pages/login.vue +++ b/frontend/src/pages/auth/login.vue @@ -93,7 +93,7 @@ async function handleLogin() {
- Pas encore de compte ? Rejoindre + Pas encore de compte ? Rejoindre
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index e5ece13..c8a1bbd 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -6,48 +6,75 @@ // Composables import {createRouter, createWebHistory} from 'vue-router' -import Index from '@/pages/index.vue' import {useAuthStore} from '@/stores/auth' +import AuthLayout from "@/layouts/AuthLayout.vue"; +import AppLayout from "@/layouts/AppLayout.vue"; +import AdminLayout from "@/layouts/AdminLayout.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ + // ----------------- GROUPE AUTHENTIFICATION ----------------- { - path: '/login', - name: 'login', - component: () => import('@/pages/login.vue'), - }, - { - path: '/join', - name: 'join', - component: () => import('@/pages/join.vue'), - }, - { - path: '/', - component: Index, - }, - { - // Cette regex capture soit un UUID, soit le mot "default" - path: '/server/:id(default|[0-9a-fA-F-]{36})', - name: 'server-dashboard', - component: () => import('@/pages/server/index.vue'), - props: true, + path: '/auth', + component: AuthLayout, children: [ { - path: 'channel/:channelId', - name: 'server-channel', - component: () => import('@/pages/server/channel/index.vue'), + path: 'login', + name: 'login', + component: () => import('@/pages/auth/login.vue'), + }, + { + path: 'join', + name: 'join', + component: () => import('@/pages/auth/join.vue'), + }, + // Vous pouvez ajouter ici 'reset-password', etc. + ], + }, + + // ----------------- GROUPE APPLICATION GÉNÉRALE ----------------- + { + path: '/', + component: AppLayout, + children: [ + { + path: '', + name: 'home', + component: () => import('@/pages/index.vue'), + }, + { + path: 'server/:id(default|[0-9a-fA-F-]{36})', + name: 'server-dashboard', + component: () => import('@/pages/server/index.vue'), props: true, + children: [ + { + path: 'channel/:channelId', + name: 'server-channel', + component: () => import('@/pages/server/channel/index.vue'), + props: true, + }, + ], }, ], }, + + // ----------------- GROUPE ADMINISTRATION ----------------- { path: '/admin', - name: 'admin-dashboard', - component: () => import('@/pages/admin/dashboard.vue'), - meta: {requiresAdmin: true} + component: AdminLayout, + meta: {requiresAdmin: true}, + children: [ + { + path: '', + name: 'admin-dashboard', + component: () => import('@/pages/admin/dashboard.vue'), + }, + // Ajoutez d'autres pages admin ici + ], }, ], }) @@ -64,7 +91,7 @@ router.beforeEach(async (to, from, next) => { if (authRequired && !authStore.isAuthenticated) { // Non connecté -> Login - next('/login') + next('/auth/login') } else if (to.name === 'login' && authStore.isAuthenticated) { // Déjà connecté -> Accueil next('/') diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index cd73e53..52100bd 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -34,8 +34,11 @@ export const useAppStore = defineStore('app', { // On s'abonne à l'événement de connexion de la gateway window.addEventListener('gateway:connected', loadAppData) + // On connecte la gateway (qui déclenchera 'gateway:connected') + await gatewayStore.connect() + // Initialisation de l'authentification (qui lancera la connexion à la gateway) - await authStore.initialize() + // await authStore.initialize() // Sécurité : si la gateway s'est déjà connectée entre-temps if (gatewayStore.status === 'connected') { diff --git a/frontend/src/stores/auth.ts b/frontend/src/stores/auth.ts index 4b12a20..03c1c47 100644 --- a/frontend/src/stores/auth.ts +++ b/frontend/src/stores/auth.ts @@ -1,6 +1,5 @@ import {defineStore} from 'pinia' import {useApi} from "@/composables/useApi"; -import {useGatewayStore} from "@/stores/gateway.ts"; export interface User { id: string @@ -13,57 +12,100 @@ export interface User { export const useAuthStore = defineStore('auth', { state: () => ({ - token: localStorage.getItem('token') || null as string | null, + // Plus de token stocké dans le localStorage ! user: null as User | null, isInitialized: false, + // Nous ne gardons ce token en mémoire que pour la connexion au WebSocket + // gatewayToken: null as string | null, }), getters: { - isAuthenticated: (state) => !!state.token && !!state.user, + isAuthenticated: (state) => !!state.user, isAdmin: (state) => state.user?.is_superuser || false, currentUser: (state) => state.user, }, actions: { async initialize() { - if (!this.token) { - this.isInitialized = true - return - } - const api = useApi() try { const response = await api.get('/auth/me') if (response.ok) { const data = await response.json() this.user = data.user - - // Initialisation du gateway - const gatewayStore = useGatewayStore() - await gatewayStore.connect() - } else { - this.logout() } } catch (e) { console.error("Auth initialization failed", e) - this.logout() + // this.logout() } finally { this.isInitialized = true } }, - setToken(token: string) { - this.token = token - localStorage.setItem('token', token) - // On déclenche la récupération des infos utilisateur immédiatement - return this.initialize() - }, - logout() { - this.token = null + const api = useApi() this.user = null - localStorage.removeItem('token') - // On ne redirige pas ici pour laisser le router ou le composant décider + api.post('/auth/logout') + // Note : si vous implémentez une route /auth/logout côté Axum, + // elle devra nettoyer le cookie en renvoyant un Set-Cookie expiré. } } -}) \ No newline at end of file +}) + +////// Version with token + local storage +// export const useAuthStore = defineStore('auth', { +// state: () => ({ +// token: localStorage.getItem('token') || null as string | null, +// user: null as User | null, +// isInitialized: false, +// }), +// +// getters: { +// isAuthenticated: (state) => !!state.token && !!state.user, +// isAdmin: (state) => state.user?.is_superuser || false, +// currentUser: (state) => state.user, +// }, +// +// actions: { +// async initialize() { +// if (!this.token) { +// this.isInitialized = true +// return +// } +// +// const api = useApi() +// try { +// const response = await api.get('/auth/me') +// if (response.ok) { +// const data = await response.json() +// this.user = data.user +// +// // Initialisation du gateway +// const gatewayStore = useGatewayStore() +// await gatewayStore.connect() +// } else { +// this.logout() +// } +// } catch (e) { +// console.error("Auth initialization failed", e) +// this.logout() +// } finally { +// this.isInitialized = true +// } +// }, +// +// setToken(token: string) { +// this.token = token +// localStorage.setItem('token', token) +// // On déclenche la récupération des infos utilisateur immédiatement +// return this.initialize() +// }, +// +// logout() { +// this.token = null +// this.user = null +// localStorage.removeItem('token') +// // On ne redirige pas ici pour laisser le router ou le composant décider +// } +// } +// }) \ No newline at end of file diff --git a/frontend/src/stores/category.ts b/frontend/src/stores/category.ts index 5070d8f..34c50c8 100644 --- a/frontend/src/stores/category.ts +++ b/frontend/src/stores/category.ts @@ -8,7 +8,7 @@ export const useCategoryStore = defineStore("category", { actions: { async fetchCategories() { let api = useApi(); - let response = await api.get("/api/categories"); + let response = await api.get("/categories"); this.categories = await response.json(); } } diff --git a/frontend/src/stores/channel.ts b/frontend/src/stores/channel.ts index cf1125e..d8b66be 100644 --- a/frontend/src/stores/channel.ts +++ b/frontend/src/stores/channel.ts @@ -11,7 +11,7 @@ export const useChannelStore = defineStore('channel', { actions: { async fetchChannels() { let api = useApi(); - let response = await api.get("/api/channels"); + let response = await api.get("/channels"); this.channels = await response.json(); } } diff --git a/frontend/src/stores/gateway.ts b/frontend/src/stores/gateway.ts index 0decc86..86ecd6f 100644 --- a/frontend/src/stores/gateway.ts +++ b/frontend/src/stores/gateway.ts @@ -1,6 +1,5 @@ import {defineStore} from 'pinia'; import {useAppStore} from "@/stores/app.ts"; -import {useAuthStore} from "@/stores/auth.ts"; type GatewayStatus = 'disconnected' | 'connecting' | 'connected' | 'error' @@ -18,20 +17,21 @@ export const useGatewayStore = defineStore('gateway', { } const appStore = useAppStore() - const authStore = useAuthStore() - + // const authStore = useAuthStore() this.status = 'connecting' - const token = authStore.token - if (!token) { - this.status = 'error' - return - } + // version token + // const token = authStore.token + // if (!token) { + // this.status = 'error' + // return + // } const apiUri = appStore.baseurl ? new URL(appStore.baseurl) : new URL(window.location.href) const wsProtocol = apiUri.protocol === 'https:' ? 'wss:' : 'ws:' - - const wsUrl = `${wsProtocol}//${apiUri.host}/ws/gateway?token=${encodeURIComponent(token)}` + // version token + // const wsUrl = `${wsProtocol}//${apiUri.host}/ws/gateway?token=${encodeURIComponent(token)}` + const wsUrl = `${wsProtocol}//${apiUri.host}/ws/gateway` const socket = new WebSocket(wsUrl) socket.onopen = () => { diff --git a/frontend/src/stores/server.ts b/frontend/src/stores/server.ts index b4178a4..5f2d594 100644 --- a/frontend/src/stores/server.ts +++ b/frontend/src/stores/server.ts @@ -8,7 +8,7 @@ export const useServerStore = defineStore("server", { actions: { async fetchServers() { let api = useApi(); - const response = await api.get("/api/servers"); + const response = await api.get("/servers"); this.servers = await response.json(); } } diff --git a/frontend/vite.config.mts b/frontend/vite.config.mts index 83820fb..0ea712a 100644 --- a/frontend/vite.config.mts +++ b/frontend/vite.config.mts @@ -1,14 +1,14 @@ -import { fileURLToPath, URL } from 'node:url' +import {fileURLToPath, URL} from 'node:url' import Vue from '@vitejs/plugin-vue' import Fonts from 'unplugin-fonts/vite' -import { defineConfig } from 'vite' -import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify' +import {defineConfig} from 'vite' +import Vuetify, {transformAssetUrls} from 'vite-plugin-vuetify' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ Vue({ - template: { transformAssetUrls }, + template: {transformAssetUrls}, }), // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme Vuetify({ @@ -29,7 +29,7 @@ export default defineConfig({ }, }), ], - define: { 'process.env': {} }, + define: {'process.env': {}}, resolve: { alias: { '@': fileURLToPath(new URL('src', import.meta.url)), @@ -46,5 +46,11 @@ export default defineConfig({ }, server: { port: 3000, + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + }, + }, }, }) diff --git a/migration/src/m20220101_000001_create_table.rs b/migration/src/m20220101_000001_create_table.rs index a9a2afe..a75e1db 100644 --- a/migration/src/m20220101_000001_create_table.rs +++ b/migration/src/m20220101_000001_create_table.rs @@ -125,6 +125,16 @@ impl MigrationTrait for Migration { .integer() .not_null(), ) + .col( + ColumnDef::new(Alias::new("default_channel_permissions")) + .big_integer() + .null(), + ) + .col( + ColumnDef::new(Alias::new("default_voice_permissions")) + .big_integer() + .null(), + ) .col(ColumnDef::new(Alias::new("name")).string().null()) .col( ColumnDef::new(Alias::new("created_at")) diff --git a/src/auth/token.rs b/src/auth/token.rs index 34e3330..3235c93 100644 --- a/src/auth/token.rs +++ b/src/auth/token.rs @@ -36,13 +36,11 @@ pub fn create_jwt( } pub fn verify_jwt(token: &str, secret: &str) -> Result { - println!("Verifying token: {}", token); let validation = Validation::default(); let token_data = decode::( token, &DecodingKey::from_secret(secret.as_ref()), &validation, )?; - println!("Token data: {:?}", token_data); Ok(token_data.claims) } diff --git a/src/http/middleware.rs b/src/http/middleware.rs index 5af2818..38d8c51 100644 --- a/src/http/middleware.rs +++ b/src/http/middleware.rs @@ -5,6 +5,7 @@ use axum::{ middleware::Next, response::{IntoResponse, Response}, }; +use axum_extra::extract::CookieJar; use std::sync::Arc; use std::time::Instant; use tracing::{info, Instrument}; @@ -103,6 +104,11 @@ pub async fn auth_middleware( None } }) + .or_else(|| { + // Grâce à CookieJar, on extrait proprement le cookie "token" ou "jwt" + let jar = CookieJar::from_headers(req.headers()); + jar.get("token").map(|cookie| cookie.value().to_string()) + }) .or_else(|| { req.uri().query().and_then(|q| { form_urlencoded::parse(q.as_bytes()) diff --git a/src/models/channel.rs b/src/models/channel.rs index 76f3e15..570e547 100644 --- a/src/models/channel.rs +++ b/src/models/channel.rs @@ -32,7 +32,8 @@ pub struct Model { pub name: Option, pub created_at: DateTimeUtc, pub updated_at: DateTimeUtc, - pub default_permissions: Option, + pub default_channel_permissions: Option, + pub default_voice_permissions: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/routes/auth/handlers.rs b/src/routes/auth/handlers.rs index d7e3379..53d489e 100644 --- a/src/routes/auth/handlers.rs +++ b/src/routes/auth/handlers.rs @@ -6,11 +6,13 @@ use crate::http::error::HTTPError; use crate::routes::user::mapper::user_model_to_user_response; use axum::extract::State; use axum::Json; +use axum_extra::extract::cookie::{Cookie, SameSite}; +use axum_extra::extract::CookieJar; use sea_orm::ActiveModelBehavior; #[utoipa::path( - get, - path = "/auth/login", + post, + path = "/auth/bearer-login", request_body = LoginRequest, responses( (status = 200, description = "Login successful", body = LoginResponse), @@ -18,7 +20,7 @@ use sea_orm::ActiveModelBehavior; ), tag = "Auth" )] -pub async fn login_user_pw( +pub async fn login_bearer( State(state): State, Json(payload): Json, ) -> Result, HTTPError> { @@ -41,6 +43,69 @@ pub async fn login_user_pw( Ok(Json(LoginResponse { token })) } +#[utoipa::path( + post, + path = "/auth/login", + request_body = LoginRequest, + responses( + (status = 200, description = "Login successful with cookie set", body = LoginResponse), + (status = 401, description = "Unauthorized") + ), + tag = "Auth" +)] +pub async fn login_cookie( + State(state): State, + jar: CookieJar, + Json(payload): Json, +) -> Result<(CookieJar, Json), HTTPError> { + let user = state + .repositories + .user + .check_password(&payload.username, &payload.password) + .await + .map_err(|_| HTTPError::Unauthorized)?; + + let token = create_jwt( + user.id, + &user.username, + user.is_superuser, + &state.config.jwt.secret, + state.config.jwt.duration, + ) + .map_err(|_| HTTPError::InternalServerError("Failed to create JWT token".to_string()))?; + + // Création du cookie sécurisé contenant le token JWT + let cookie = Cookie::build(("token", token.clone())) + .path("/") + .http_only(true) + .same_site(SameSite::Lax) + .secure(false) // Mettez à true si vous forcez le HTTPS en production + .build(); + + let updated_jar = jar.add(cookie); + + Ok((updated_jar, Json(LoginResponse { token }))) +} + +#[utoipa::path( + post, + path = "/auth/logout", + responses( + (status = 200, description = "Logout successful") + ), + tag = "Auth" +)] +pub async fn logout_cookie(jar: CookieJar) -> Result { + // On crée un cookie expiré en lui donnant une durée négative de 1 seconde (ou Duration::ZERO) + let cookie = Cookie::build(("token", "")) + .path("/") + .max_age(time::Duration::seconds(-1)) + .build(); + + let updated_jar = jar.add(cookie); + Ok(updated_jar) +} + #[utoipa::path( post, path = "/auth/me", diff --git a/src/routes/auth/routes.rs b/src/routes/auth/routes.rs index ee383ed..2eecbf7 100644 --- a/src/routes/auth/routes.rs +++ b/src/routes/auth/routes.rs @@ -5,6 +5,7 @@ use axum::Router; pub fn router() -> OxRouter { Router::new() - .route("/auth/login", post(handlers::login_user_pw)) + .route("/auth/login", post(handlers::login_cookie)) + .route("/auth/bearer-login", post(handlers::login_bearer)) .route("/auth/me", get(handlers::me)) } diff --git a/src/routes/channel/dto.rs b/src/routes/channel/dto.rs index 1e3f8f7..d6ab425 100644 --- a/src/routes/channel/dto.rs +++ b/src/routes/channel/dto.rs @@ -13,7 +13,8 @@ pub struct CreateChannelRequest { pub channel_type: ChannelType, #[schema(example = "général")] pub name: Option, - pub default_permissions: Option, + pub default_channel_permissions: Option, + pub default_voice_permissions: Option, } #[derive(Debug, Serialize, Deserialize, ToSchema)] @@ -23,7 +24,8 @@ pub struct UpdateChannelRequest { pub position: i32, pub channel_type: ChannelType, pub name: Option, - pub default_permissions: Option, + pub default_channel_permissions: Option, + pub default_voice_permissions: Option, } #[derive(Debug, Serialize, Deserialize, ToSchema)] @@ -36,5 +38,6 @@ pub struct ChannelResponse { pub name: Option, pub created_at: DateTime, pub updated_at: DateTime, - pub default_permissions: Option, + pub default_channel_permissions: Option, + pub default_voice_permissions: Option, } diff --git a/src/routes/channel/mapper.rs b/src/routes/channel/mapper.rs index 8f23fc8..566dcdd 100644 --- a/src/routes/channel/mapper.rs +++ b/src/routes/channel/mapper.rs @@ -13,7 +13,8 @@ pub fn channel_model_to_channel_response(model: channel::Model) -> ChannelRespon name: model.name, created_at: model.created_at, updated_at: model.updated_at, - default_permissions: model.default_permissions, + default_channel_permissions: model.default_channel_permissions.map(|p| p as u64), + default_voice_permissions: model.default_voice_permissions.map(|p| p as u64), } } @@ -25,7 +26,8 @@ pub fn create_request_to_am(req: CreateChannelRequest) -> channel::ActiveModel { position: Set(req.position), channel_type: Set(req.channel_type), name: Set(req.name), - default_permissions: Set(req.default_permissions), + default_channel_permissions: Set(req.default_channel_permissions.map(|p| p as i64)), + default_voice_permissions: Set(req.default_voice_permissions.map(|p| p as i64)), ..Default::default() } } @@ -38,7 +40,8 @@ pub fn update_request_to_am(id: Uuid, req: UpdateChannelRequest) -> channel::Act position: Set(req.position), channel_type: Set(req.channel_type), name: Set(req.name), - default_permissions: Set(req.default_permissions), + default_channel_permissions: Set(req.default_channel_permissions.map(|p| p as i64)), + default_voice_permissions: Set(req.default_voice_permissions.map(|p| p as i64)), ..Default::default() } } diff --git a/src/routes/gateway/handlers.rs b/src/routes/gateway/handlers.rs index 11de1ab..aef0c51 100644 --- a/src/routes/gateway/handlers.rs +++ b/src/routes/gateway/handlers.rs @@ -4,7 +4,7 @@ use crate::models::user::Model as User; use crate::routes::gateway::GatewayClient; use axum::{ extract::{ - ws::{Message, WebSocket, WebSocketUpgrade}, Query, + ws::{Message, WebSocket, WebSocketUpgrade}, State, }, response::IntoResponse, @@ -19,7 +19,6 @@ pub struct WsQuery { } pub async fn ws_handler( - Query(query): Query, ws: WebSocketUpgrade, State(state): State, CurrentUser(user): CurrentUser, diff --git a/src/routes/openapi.rs b/src/routes/openapi.rs index cb63bee..2c90760 100644 --- a/src/routes/openapi.rs +++ b/src/routes/openapi.rs @@ -6,7 +6,9 @@ use utoipa::{Modify, OpenApi}; #[derive(OpenApi)] #[openapi( paths( - auth::handlers::login_user_pw, + auth::handlers::login_bearer, + auth::handlers::login_cookie, + auth::handlers::logout_cookie, auth::handlers::me, user::handlers::get_all, user::handlers::get_by_id,