Init
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1656,6 +1656,7 @@ dependencies = [
|
|||||||
"sea-orm",
|
"sea-orm",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_repr",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
@@ -2351,6 +2352,17 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_repr"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.110",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ chrono = "0.4"
|
|||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
serde = { version = "1.0", features = ["default", "derive"] }
|
serde = { version = "1.0", features = ["default", "derive"] }
|
||||||
serde_json = { version = "1.0.145", features = ["default"]}
|
serde_json = { version = "1.0.145", features = ["default"]}
|
||||||
|
serde_repr = "0.1"
|
||||||
toml = "0.9"
|
toml = "0.9"
|
||||||
validator = { version = "0.20", features = ["derive"] }
|
validator = { version = "0.20", features = ["derive"] }
|
||||||
uuid = {version = "1", features = ["v4", "v7", "fast-rng", "serde"]}
|
uuid = {version = "1", features = ["v4", "v7", "fast-rng", "serde"]}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<h3>category : {{category.name}} <button @click="remove">Remove</button></h3>
|
<h3>category : {{category.name}} ({{category.id}})<button @click="remove">Remove</button></h3>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<h3>channel : {{channel.name}} <button @click="remove">Remove</button></h3>
|
<h3>channel : {{channel.name}} <button @click="remove">Remove</button></h3>
|
||||||
<p>Type: {{ channel.channel_type }}</p>
|
<ul>
|
||||||
|
<li v-if="channel.server_id">Server: {{ channel.server_id }}</li>
|
||||||
|
<li v-if="channel.category_id">Category: {{ channel.category_id }}</li>
|
||||||
|
<li>Type: {{ channel.channel_type }}</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<h3>server : {{server.name}} <button @click="remove">Remove</button></h3>
|
<h3>server : {{server.name}} ({{server.id}}) <button @click="remove">Remove</button></h3>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -63,6 +63,12 @@ impl MigrationTrait for Migration {
|
|||||||
.string()
|
.string()
|
||||||
.not_null()
|
.not_null()
|
||||||
)
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Alias::new("position"))
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.default(0)
|
||||||
|
)
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(Alias::new("created_at"))
|
ColumnDef::new(Alias::new("created_at"))
|
||||||
.date_time()
|
.date_time()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub struct Model {
|
|||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub server_id: Uuid,
|
pub server_id: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub position: i32,
|
||||||
pub created_at: DateTime,
|
pub created_at: DateTime,
|
||||||
pub updated_at: DateTime,
|
pub updated_at: DateTime,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,19 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use sea_orm::prelude::async_trait::async_trait;
|
use sea_orm::prelude::async_trait::async_trait;
|
||||||
use sea_orm::Set;
|
use sea_orm::Set;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
|
||||||
|
#[sea_orm(rs_type = "i32", db_type = "Integer")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ChannelType {
|
||||||
|
#[sea_orm(num_value = 0)]
|
||||||
|
Text,
|
||||||
|
#[sea_orm(num_value = 1)]
|
||||||
|
Voice,
|
||||||
|
#[sea_orm(num_value = 3)]
|
||||||
|
DM,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "channel")]
|
#[sea_orm(table_name = "channel")]
|
||||||
@@ -12,7 +25,7 @@ pub struct Model {
|
|||||||
pub server_id: Option<Uuid>,
|
pub server_id: Option<Uuid>,
|
||||||
pub category_id: Option<Uuid>,
|
pub category_id: Option<Uuid>,
|
||||||
pub position: i32,
|
pub position: i32,
|
||||||
pub channel_type: i32,
|
pub channel_type: ChannelType,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub created_at: DateTime,
|
pub created_at: DateTime,
|
||||||
pub updated_at: DateTime,
|
pub updated_at: DateTime,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use sea_orm::{DbErr, EntityTrait, ActiveModelTrait};
|
use sea_orm::{DbErr, EntityTrait, ActiveModelTrait, QueryFilter, ColumnTrait, QueryOrder};
|
||||||
use crate::models::server;
|
use uuid::Uuid;
|
||||||
|
use crate::models::{category, channel, server};
|
||||||
use crate::repositories::RepositoryContext;
|
use crate::repositories::RepositoryContext;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -35,3 +36,78 @@ impl ServerRepository {
|
|||||||
Ok(res.rows_affected > 0)
|
Ok(res.rows_affected > 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ServerExplorerItem {
|
||||||
|
Category(category::Model, Vec<channel::Model>),
|
||||||
|
Channel(channel::Model),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour pouvoir trier facilement
|
||||||
|
impl ServerExplorerItem {
|
||||||
|
fn position(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
ServerExplorerItem::Category(cat, _) => cat.position,
|
||||||
|
ServerExplorerItem::Channel(chan) => chan.position,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServerLayout {
|
||||||
|
pub items: Vec<ServerExplorerItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
impl ServerRepository {
|
||||||
|
pub async fn get_channels_tree(&self, server_id: Uuid) -> Result<ServerLayout, DbErr> {
|
||||||
|
// 1. Récupération des catégories avec leurs channels
|
||||||
|
let categories_with_channels = category::Entity::find()
|
||||||
|
.filter(category::Column::ServerId.eq(server_id))
|
||||||
|
.find_with_related(channel::Entity)
|
||||||
|
.all(&self.context.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// 2. Récupération des channels orphelins (sans catégorie)
|
||||||
|
let orphan_channels = channel::Entity::find()
|
||||||
|
.filter(channel::Column::ServerId.eq(server_id))
|
||||||
|
.filter(channel::Column::CategoryId.is_null())
|
||||||
|
.all(&self.context.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// 3. Transformation et tri des enfants
|
||||||
|
let mut items: Vec<ServerExplorerItem> = Vec::new();
|
||||||
|
|
||||||
|
for (cat, mut channels) in categories_with_channels {
|
||||||
|
// On trie les channels internes (obligatoire car SQL ne garantit aucun ordre ici)
|
||||||
|
channels.sort_by(|a, b| {
|
||||||
|
a.position.cmp(&b.position).then(a.created_at.cmp(&b.created_at))
|
||||||
|
});
|
||||||
|
items.push(ServerExplorerItem::Category(cat, channels));
|
||||||
|
}
|
||||||
|
|
||||||
|
for chan in orphan_channels {
|
||||||
|
items.push(ServerExplorerItem::Channel(chan));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Tri final de la liste globale (Mélange catégories et orphelins)
|
||||||
|
items.sort_by(|a, b| {
|
||||||
|
let pos_cmp = a.position().cmp(&b.position());
|
||||||
|
|
||||||
|
if pos_cmp == std::cmp::Ordering::Equal {
|
||||||
|
// Départage par date si position identique
|
||||||
|
let date_a = match a {
|
||||||
|
ServerExplorerItem::Category(c, _) => c.created_at,
|
||||||
|
ServerExplorerItem::Channel(c) => c.created_at,
|
||||||
|
};
|
||||||
|
let date_b = match b {
|
||||||
|
ServerExplorerItem::Category(c, _) => c.created_at,
|
||||||
|
ServerExplorerItem::Channel(c) => c.created_at,
|
||||||
|
};
|
||||||
|
date_a.cmp(&date_b)
|
||||||
|
} else {
|
||||||
|
pos_cmp
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(ServerLayout { items })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ use serde::{Serialize, Deserialize};
|
|||||||
use sea_orm::ActiveValue::Set;
|
use sea_orm::ActiveValue::Set;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use crate::models::channel;
|
use crate::models::channel;
|
||||||
|
use crate::models::channel::ChannelType;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ChannelSerializer {
|
pub struct ChannelSerializer {
|
||||||
@@ -11,7 +12,7 @@ pub struct ChannelSerializer {
|
|||||||
pub category_id: Option<Uuid>,
|
pub category_id: Option<Uuid>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub position: Option<i32>,
|
pub position: Option<i32>,
|
||||||
pub channel_type: i32,
|
pub channel_type: ChannelType,
|
||||||
|
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
pub created_at: Option<String>,
|
pub created_at: Option<String>,
|
||||||
|
|||||||
Reference in New Issue
Block a user