feat: implement is_above for roles and reuse same functions from channels!
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
This commit is contained in:
parent
39d01bb0d0
commit
1aa38631b8
8 changed files with 81 additions and 41 deletions
3
migrations/2025-05-27-105059_redo_role_ordering/down.sql
Normal file
3
migrations/2025-05-27-105059_redo_role_ordering/down.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE roles ADD COLUMN position int NOT NULL DEFAULT 0;
|
||||
ALTER TABLE roles DROP COLUMN is_above;
|
3
migrations/2025-05-27-105059_redo_role_ordering/up.sql
Normal file
3
migrations/2025-05-27-105059_redo_role_ordering/up.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
-- Your SQL goes here
|
||||
ALTER TABLE roles DROP COLUMN position;
|
||||
ALTER TABLE roles ADD COLUMN is_above UUID UNIQUE REFERENCES roles(uuid) DEFAULT NULL;
|
|
@ -14,7 +14,6 @@ use crate::{
|
|||
#[derive(Deserialize)]
|
||||
struct GuildInfo {
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
}
|
||||
|
||||
pub fn web() -> Scope {
|
||||
|
@ -41,7 +40,6 @@ pub async fn create(
|
|||
let guild = Guild::new(
|
||||
&mut conn,
|
||||
guild_info.name.clone(),
|
||||
guild_info.description.clone(),
|
||||
uuid,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Channel, Member},
|
||||
utils::{get_auth_header, order_channels},
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Channel, Member}, utils::{get_auth_header, order_by_is_above}, Data
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
||||
|
@ -43,7 +39,7 @@ pub async fn get(
|
|||
|
||||
let channels = Channel::fetch_all(&data.pool, guild_uuid).await?;
|
||||
|
||||
let channels_ordered = order_channels(channels).await?;
|
||||
let channels_ordered = order_by_is_above(channels).await?;
|
||||
|
||||
data.set_cache_key(
|
||||
format!("{}_channels", guild_uuid),
|
||||
|
|
|
@ -3,11 +3,7 @@ use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
|||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
structs::{Member, Role},
|
||||
utils::get_auth_header,
|
||||
api::v1::auth::check_access_token, error::Error, structs::{Member, Role}, utils::{get_auth_header, order_by_is_above}, Data
|
||||
};
|
||||
|
||||
pub mod uuid;
|
||||
|
@ -43,10 +39,12 @@ pub async fn get(
|
|||
|
||||
let roles = Role::fetch_all(&mut conn, guild_uuid).await?;
|
||||
|
||||
data.set_cache_key(format!("{}_roles", guild_uuid), roles.clone(), 1800)
|
||||
let roles_ordered = order_by_is_above(roles).await?;
|
||||
|
||||
data.set_cache_key(format!("{}_roles", guild_uuid), roles_ordered.clone(), 1800)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(roles))
|
||||
Ok(HttpResponse::Ok().json(roles_ordered))
|
||||
}
|
||||
|
||||
#[post("{uuid}/roles")]
|
||||
|
|
|
@ -105,8 +105,8 @@ diesel::table! {
|
|||
#[max_length = 50]
|
||||
name -> Varchar,
|
||||
color -> Int4,
|
||||
position -> Int4,
|
||||
permissions -> Int8,
|
||||
is_above -> Nullable<Uuid>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ use diesel::{
|
|||
update,
|
||||
};
|
||||
use diesel_async::{RunQueryDsl, pooled_connection::AsyncDieselConnectionManager};
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task;
|
||||
use url::Url;
|
||||
|
@ -15,9 +14,17 @@ use crate::{
|
|||
Conn, Data,
|
||||
error::Error,
|
||||
schema::*,
|
||||
utils::{image_check, order_channels},
|
||||
utils::{image_check, order_by_is_above},
|
||||
};
|
||||
|
||||
pub trait HasUuid {
|
||||
fn uuid(&self) -> &Uuid;
|
||||
}
|
||||
|
||||
pub trait HasIsAbove {
|
||||
fn is_above(&self) -> Option<&Uuid>;
|
||||
}
|
||||
|
||||
fn load_or_empty<T>(
|
||||
query_result: Result<Vec<T>, diesel::result::Error>,
|
||||
) -> Result<Vec<T>, diesel::result::Error> {
|
||||
|
@ -79,6 +86,18 @@ pub struct ChannelPermission {
|
|||
pub permissions: i64,
|
||||
}
|
||||
|
||||
impl HasUuid for Channel {
|
||||
fn uuid(&self) -> &Uuid {
|
||||
self.uuid.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasIsAbove for Channel {
|
||||
fn is_above(&self) -> Option<&Uuid> {
|
||||
self.is_above.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub async fn fetch_all(
|
||||
pool: &deadpool::managed::Pool<
|
||||
|
@ -129,11 +148,7 @@ impl Channel {
|
|||
|
||||
let channels = Self::fetch_all(&data.pool, guild_uuid).await?;
|
||||
|
||||
debug!("{:?}", channels);
|
||||
|
||||
let channels_ordered = order_channels(channels).await?;
|
||||
|
||||
debug!("{:?}", channels_ordered);
|
||||
let channels_ordered = order_by_is_above(channels).await?;
|
||||
|
||||
let last_channel = channels_ordered.last();
|
||||
|
||||
|
@ -145,8 +160,6 @@ impl Channel {
|
|||
is_above: None,
|
||||
};
|
||||
|
||||
debug!("New Channel: {:?}", new_channel);
|
||||
|
||||
insert_into(channels::table)
|
||||
.values(new_channel.clone())
|
||||
.execute(&mut conn)
|
||||
|
@ -359,7 +372,6 @@ impl Guild {
|
|||
pub async fn new(
|
||||
conn: &mut Conn,
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
owner_uuid: Uuid,
|
||||
) -> Result<Self, Error> {
|
||||
let guild_uuid = Uuid::now_v7();
|
||||
|
@ -367,7 +379,7 @@ impl Guild {
|
|||
let guild_builder = GuildBuilder {
|
||||
uuid: guild_uuid,
|
||||
name: name.clone(),
|
||||
description: description.clone(),
|
||||
description: None,
|
||||
icon: None,
|
||||
owner_uuid,
|
||||
};
|
||||
|
@ -394,7 +406,7 @@ impl Guild {
|
|||
Ok(Guild {
|
||||
uuid: guild_uuid,
|
||||
name,
|
||||
description,
|
||||
description: None,
|
||||
icon: None,
|
||||
owner_uuid,
|
||||
roles: vec![],
|
||||
|
@ -492,10 +504,22 @@ pub struct Role {
|
|||
guild_uuid: Uuid,
|
||||
name: String,
|
||||
color: i32,
|
||||
position: i32,
|
||||
is_above: Option<Uuid>,
|
||||
permissions: i64,
|
||||
}
|
||||
|
||||
impl HasUuid for Role {
|
||||
fn uuid(&self) -> &Uuid {
|
||||
self.uuid.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasIsAbove for Role {
|
||||
fn is_above(&self) -> Option<&Uuid> {
|
||||
self.is_above.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub async fn fetch_all(conn: &mut Conn, guild_uuid: Uuid) -> Result<Vec<Self>, Error> {
|
||||
use roles::dsl;
|
||||
|
@ -524,21 +548,36 @@ impl Role {
|
|||
pub async fn new(conn: &mut Conn, guild_uuid: Uuid, name: String) -> Result<Self, Error> {
|
||||
let role_uuid = Uuid::now_v7();
|
||||
|
||||
let role = Role {
|
||||
let roles = Self::fetch_all(conn, guild_uuid).await?;
|
||||
|
||||
let roles_ordered = order_by_is_above(roles).await?;
|
||||
|
||||
let last_role = roles_ordered.last();
|
||||
|
||||
let new_role = Role {
|
||||
uuid: role_uuid,
|
||||
guild_uuid,
|
||||
name,
|
||||
color: 16777215,
|
||||
position: 0,
|
||||
is_above: None,
|
||||
permissions: 0,
|
||||
};
|
||||
|
||||
insert_into(roles::table)
|
||||
.values(role.clone())
|
||||
.values(new_role.clone())
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(role)
|
||||
if let Some(old_last_role) = last_role {
|
||||
use roles::dsl;
|
||||
update(roles::table)
|
||||
.filter(dsl::uuid.eq(old_last_role.uuid))
|
||||
.set(dsl::is_above.eq(new_role.uuid))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(new_role)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
19
src/utils.rs
19
src/utils.rs
|
@ -9,7 +9,7 @@ use hex::encode;
|
|||
use redis::RedisError;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{Data, error::Error, structs::Channel};
|
||||
use crate::{error::Error, structs::{HasIsAbove, HasUuid}, Data};
|
||||
|
||||
pub fn get_auth_header(headers: &HeaderMap) -> Result<&str, Error> {
|
||||
let auth_token = headers.get(actix_web::http::header::AUTHORIZATION);
|
||||
|
@ -119,22 +119,25 @@ pub fn image_check(icon: BytesMut) -> Result<String, Error> {
|
|||
))
|
||||
}
|
||||
|
||||
pub async fn order_channels(mut channels: Vec<Channel>) -> Result<Vec<Channel>, Error> {
|
||||
pub async fn order_by_is_above<T>(mut items: Vec<T>) -> Result<Vec<T>, Error>
|
||||
where
|
||||
T: HasUuid + HasIsAbove,
|
||||
{
|
||||
let mut ordered = Vec::new();
|
||||
|
||||
// Find head
|
||||
let head_pos = channels
|
||||
let head_pos = items
|
||||
.iter()
|
||||
.position(|channel| !channels.iter().any(|i| i.is_above == Some(channel.uuid)));
|
||||
.position(|item| !items.iter().any(|i| i.is_above() == Some(item.uuid())));
|
||||
|
||||
if let Some(pos) = head_pos {
|
||||
ordered.push(channels.swap_remove(pos));
|
||||
ordered.push(items.swap_remove(pos));
|
||||
|
||||
while let Some(next_pos) = channels
|
||||
while let Some(next_pos) = items
|
||||
.iter()
|
||||
.position(|channel| Some(channel.uuid) == ordered.last().unwrap().is_above)
|
||||
.position(|item| Some(item.uuid()) == ordered.last().unwrap().is_above())
|
||||
{
|
||||
ordered.push(channels.swap_remove(next_pos));
|
||||
ordered.push(items.swap_remove(next_pos));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue