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 @@
+
+
+
+
+
+ Console d'Administration
+
+ Retour à l'App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 @@
+
+
+
+
+
+
+
+
+
+ mdi-square
+
+ mdi-circle
+
+ mdi-triangle
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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,