init
This commit is contained in:
@@ -243,12 +243,6 @@ impl MigrationTrait for Migration {
|
||||
)
|
||||
.col(ColumnDef::new(Alias::new("server_id")).uuid().not_null())
|
||||
.col(ColumnDef::new(Alias::new("name")).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("position"))
|
||||
.integer()
|
||||
.not_null()
|
||||
.default(0),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("created_at"))
|
||||
.timestamp_with_time_zone()
|
||||
@@ -285,12 +279,6 @@ impl MigrationTrait for Migration {
|
||||
)
|
||||
.col(ColumnDef::new(Alias::new("server_id")).uuid().null())
|
||||
.col(ColumnDef::new(Alias::new("category_id")).uuid().null())
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("position"))
|
||||
.integer()
|
||||
.not_null()
|
||||
.default(0),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("channel_type"))
|
||||
.integer()
|
||||
@@ -327,6 +315,86 @@ impl MigrationTrait for Migration {
|
||||
)
|
||||
.await?;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Ordre des catégories et des canaux (Polymorphique)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Alias::new("server_item_order"))
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("id"))
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Alias::new("server_id")).uuid().not_null())
|
||||
.col(ColumnDef::new(Alias::new("resource_id")).uuid().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("resource_type"))
|
||||
.integer()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("parent_category_id"))
|
||||
.uuid()
|
||||
.null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("order_key"))
|
||||
.big_integer()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("created_at"))
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("updated_at"))
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_server_item_order_server")
|
||||
.from(Alias::new("server_item_order"), Alias::new("server_id"))
|
||||
.to(Alias::new("server"), Alias::new("id"))
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_server_item_order_parent_category")
|
||||
.from(
|
||||
Alias::new("server_item_order"),
|
||||
Alias::new("parent_category_id"),
|
||||
)
|
||||
.to(Alias::new("category"), Alias::new("id"))
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.index(
|
||||
Index::create()
|
||||
.name("uq_server_item_order_resource")
|
||||
.col(Alias::new("server_id"))
|
||||
.col(Alias::new("resource_type"))
|
||||
.col(Alias::new("resource_id"))
|
||||
.unique(),
|
||||
)
|
||||
.index(
|
||||
Index::create()
|
||||
.name("idx_server_item_order_scope")
|
||||
.col(Alias::new("server_id"))
|
||||
.col(Alias::new("parent_category_id"))
|
||||
.col(Alias::new("order_key")),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Membres des canaux
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -716,7 +784,6 @@ impl MigrationTrait for Migration {
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
// Les tables dépendantes doivent être supprimées avant leurs parents.
|
||||
let tables = [
|
||||
"computed_permission",
|
||||
"channel_user_permission",
|
||||
@@ -726,6 +793,7 @@ impl MigrationTrait for Migration {
|
||||
"attachment",
|
||||
"message",
|
||||
"channel_user",
|
||||
"server_item_order",
|
||||
"channel",
|
||||
"category",
|
||||
"role_user",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19
|
||||
|
||||
use sea_orm::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::prelude::async_trait::async_trait;
|
||||
use sea_orm::Set;
|
||||
|
||||
#[sea_orm::model]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
@@ -12,7 +12,6 @@ pub struct Model {
|
||||
pub id: Uuid,
|
||||
pub server_id: Uuid,
|
||||
pub name: String,
|
||||
pub position: i32,
|
||||
pub created_at: DateTimeUtc,
|
||||
pub updated_at: DateTimeUtc,
|
||||
#[sea_orm(has_many)]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.19
|
||||
|
||||
use sea_orm::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::prelude::async_trait::async_trait;
|
||||
use sea_orm::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
@@ -28,7 +28,6 @@ pub struct Model {
|
||||
pub id: Uuid,
|
||||
pub server_id: Option<Uuid>,
|
||||
pub category_id: Option<Uuid>,
|
||||
pub position: i32,
|
||||
pub channel_type: ChannelType,
|
||||
pub name: Option<String>,
|
||||
pub created_at: DateTimeUtc,
|
||||
|
||||
@@ -13,6 +13,7 @@ pub mod message;
|
||||
pub mod role;
|
||||
pub mod role_user;
|
||||
pub mod server;
|
||||
pub mod server_item_order;
|
||||
pub mod server_role_permission;
|
||||
pub mod server_user;
|
||||
pub mod server_user_permission;
|
||||
|
||||
@@ -9,6 +9,7 @@ pub use super::message::Entity as Message;
|
||||
pub use super::role::Entity as Group;
|
||||
pub use super::role_user::Entity as GroupMember;
|
||||
pub use super::server::Entity as Server;
|
||||
pub use super::server_item_order::Entity as ServerItemOrder;
|
||||
pub use super::server_role_permission::Entity as ServerRolePermission;
|
||||
pub use super::server_user::Entity as ServerUser;
|
||||
pub use super::server_user_permission::Entity as ServerUserPermission;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
use sea_orm::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::prelude::async_trait::async_trait;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize, ToSchema,
|
||||
)]
|
||||
#[sea_orm(rs_type = "i32", db_type = "Integer")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum OrderedResourceType {
|
||||
#[sea_orm(num_value = 0)]
|
||||
Channel,
|
||||
|
||||
#[sea_orm(num_value = 1)]
|
||||
Category,
|
||||
}
|
||||
|
||||
#[sea_orm::model]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "server_item_order")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
pub server_id: Uuid,
|
||||
|
||||
/// UUID du channel ou de la catégorie ordonné(e).
|
||||
pub resource_id: Uuid,
|
||||
|
||||
/// Type de la ressource référencée par resource_id.
|
||||
pub resource_type: OrderedResourceType,
|
||||
|
||||
/// NULL pour la liste racine du serveur.
|
||||
/// Renseigné uniquement pour un channel placé dans une catégorie.
|
||||
pub parent_category_id: Option<Uuid>,
|
||||
|
||||
/// Clé de tri relative à (server_id, parent_category_id).
|
||||
pub order_key: i64,
|
||||
|
||||
pub created_at: DateTimeUtc,
|
||||
|
||||
pub updated_at: DateTimeUtc,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to,
|
||||
from = "server_id",
|
||||
to = "id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
pub server: HasOne<super::server::Entity>,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to,
|
||||
from = "parent_category_id",
|
||||
to = "id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
pub parent_category: HasOne<super::category::Entity>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
id: Set(Uuid::new_v4()),
|
||||
..ActiveModelTrait::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-59
@@ -1,7 +1,5 @@
|
||||
use super::types::{ServerExplorerItem, ServerTree};
|
||||
use super::{AnyResult, RepositoryContext};
|
||||
use crate::models::{
|
||||
category, channel, role, server, server_role_permission, server_user, server_user_permission,
|
||||
use crate::models::{role, server, server_role_permission, server_user, server_user_permission,
|
||||
};
|
||||
use sea_orm::prelude::*;
|
||||
use sea_orm::{ActiveModelTrait, QuerySelect, Set};
|
||||
@@ -204,59 +202,59 @@ impl ServerRepository {
|
||||
}
|
||||
|
||||
// Helpers
|
||||
impl ServerRepository {
|
||||
pub async fn get_tree(&self, server_id: Uuid) -> AnyResult<ServerTree> {
|
||||
// 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(ServerTree { items })
|
||||
}
|
||||
}
|
||||
// impl ServerRepository {
|
||||
// pub async fn get_tree(&self, server_id: Uuid) -> AnyResult<ServerTree> {
|
||||
// // 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(ServerTree { items })
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -6,14 +6,14 @@ pub enum ServerExplorerItem {
|
||||
}
|
||||
|
||||
// Pour pouvoir trier facilement
|
||||
impl ServerExplorerItem {
|
||||
pub fn position(&self) -> i32 {
|
||||
match self {
|
||||
ServerExplorerItem::Category(cat, _) => cat.position,
|
||||
ServerExplorerItem::Channel(chan) => chan.position,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl ServerExplorerItem {
|
||||
// pub fn position(&self) -> i32 {
|
||||
// match self {
|
||||
// ServerExplorerItem::Category(cat, _) => cat.position,
|
||||
// ServerExplorerItem::Channel(chan) => chan.position,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct ServerTree {
|
||||
pub items: Vec<ServerExplorerItem>,
|
||||
|
||||
@@ -8,15 +8,12 @@ pub struct CreateCategoryRequest {
|
||||
pub server_id: Uuid,
|
||||
#[schema(example = "Discussion")]
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub position: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct UpdateCategoryRequest {
|
||||
#[schema(example = "Discussion (Maj)")]
|
||||
pub name: String,
|
||||
pub position: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
@@ -24,7 +21,6 @@ pub struct CategoryResponse {
|
||||
pub id: Uuid,
|
||||
pub server_id: Uuid,
|
||||
pub name: String,
|
||||
pub position: i32,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ pub fn category_model_to_category_response(model: category::Model) -> CategoryRe
|
||||
id: model.id,
|
||||
server_id: model.server_id,
|
||||
name: model.name,
|
||||
position: model.position,
|
||||
created_at: model.created_at,
|
||||
updated_at: model.updated_at,
|
||||
}
|
||||
@@ -21,7 +20,6 @@ pub fn create_request_to_am(req: CreateCategoryRequest) -> category::ActiveModel
|
||||
id: Set(Uuid::new_v4()),
|
||||
server_id: Set(req.server_id),
|
||||
name: Set(req.name),
|
||||
position: Set(req.position),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -35,7 +33,6 @@ pub fn update_request_to_am(
|
||||
id: Set(id),
|
||||
server_id: Set(server_id),
|
||||
name: Set(req.name),
|
||||
position: Set(req.position),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ use uuid::Uuid;
|
||||
pub struct CreateChannelRequest {
|
||||
pub server_id: Option<Uuid>,
|
||||
pub category_id: Option<Uuid>,
|
||||
#[serde(default)]
|
||||
pub position: i32,
|
||||
pub channel_type: ChannelType,
|
||||
#[schema(example = "général")]
|
||||
pub name: Option<String>,
|
||||
@@ -19,7 +17,6 @@ pub struct CreateChannelRequest {
|
||||
pub struct UpdateChannelRequest {
|
||||
pub server_id: Option<Uuid>,
|
||||
pub category_id: Option<Uuid>,
|
||||
pub position: i32,
|
||||
pub channel_type: ChannelType,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
@@ -29,7 +26,6 @@ pub struct ChannelResponse {
|
||||
pub id: Uuid,
|
||||
pub server_id: Option<Uuid>,
|
||||
pub category_id: Option<Uuid>,
|
||||
pub position: i32,
|
||||
pub channel_type: ChannelType,
|
||||
pub name: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
@@ -11,7 +11,6 @@ pub fn channel_model_to_channel_response(model: channel::Model) -> ChannelRespon
|
||||
id: model.id,
|
||||
server_id: model.server_id,
|
||||
category_id: model.category_id,
|
||||
position: model.position,
|
||||
channel_type: model.channel_type,
|
||||
name: model.name,
|
||||
created_at: model.created_at,
|
||||
@@ -24,7 +23,6 @@ pub fn create_request_to_am(req: CreateChannelRequest) -> channel::ActiveModel {
|
||||
id: Set(Uuid::new_v4()),
|
||||
server_id: Set(req.server_id),
|
||||
category_id: Set(req.category_id),
|
||||
position: Set(req.position),
|
||||
channel_type: Set(req.channel_type),
|
||||
name: Set(req.name),
|
||||
..Default::default()
|
||||
@@ -36,7 +34,6 @@ pub fn update_request_to_am(id: Uuid, req: UpdateChannelRequest) -> channel::Act
|
||||
id: Set(id),
|
||||
server_id: Set(req.server_id),
|
||||
category_id: Set(req.category_id),
|
||||
position: Set(req.position),
|
||||
channel_type: Set(req.channel_type),
|
||||
name: Set(req.name),
|
||||
..Default::default()
|
||||
|
||||
Reference in New Issue
Block a user