From e5aace6e6841dada9a6517179c9fb90c5e2043b9 Mon Sep 17 00:00:00 2001 From: xeovalyte Date: Fri, 28 Feb 2025 12:12:08 +0100 Subject: [PATCH] Implement better way to define targets for messages --- server/src/database/model/message.rs | 14 +++++-- server/src/database/model/user.rs | 32 +++++++++++++++- server/src/model/message.rs | 57 ++++++++++++++++++++-------- server/src/model/user.rs | 5 +++ server/src/routes/message.rs | 44 ++++----------------- server/src/routes/user.rs | 4 +- server/src/util/cli.rs | 5 +-- 7 files changed, 101 insertions(+), 60 deletions(-) diff --git a/server/src/database/model/message.rs b/server/src/database/model/message.rs index 75eb6b3..47ec858 100644 --- a/server/src/database/model/message.rs +++ b/server/src/database/model/message.rs @@ -62,15 +62,23 @@ impl Message { Ok(()) } - pub async fn get(pool: &PgPool, channel: Channel) -> Result, sqlx::Error> { + pub async fn get( + pool: &PgPool, + channel: Channel, + member_roles: Roles, + member_groups: Groups, + ) -> Result, sqlx::Error> { let messages = sqlx::query_as!( Self, " SELECT message_id, created_at, scheduled_at, status as \"status:MessageStatus\", title, content, channel, member_groups, member_roles, thumbnail_url FROM messages WHERE status = 'sent' - AND channel & $1 > 0; + AND (channel & $1) > 0 + AND ((member_roles & $2) > 0 AND (member_groups & $3) > 0); ", - channel.bits() as i64 + channel.bits() as i64, + member_roles.bits() as i64, + member_groups.bits() as i64, ) .fetch_all(pool) .await?; diff --git a/server/src/database/model/user.rs b/server/src/database/model/user.rs index 14594ed..e6491b9 100644 --- a/server/src/database/model/user.rs +++ b/server/src/database/model/user.rs @@ -1,6 +1,6 @@ use sqlx::{PgPool, Postgres}; -use crate::model::member::Roles; +use crate::model::member::{Groups, Roles}; use super::Member as DbMember; @@ -144,6 +144,36 @@ impl UserMember { Ok(roles) } + pub async fn get_roles_groups( + pool: &PgPool, + user_id: &uuid::Uuid, + ) -> Result<(Roles, Groups), sqlx::Error> { + struct RolesGroups { + roles: i64, + groups: i64, + } + + let result = sqlx::query_as!( + RolesGroups, + " + SELECT roles, groups + FROM users_members + INNER JOIN members ON users_members.member_id = members.member_id + AND users_members.user_id = $1; + ", + user_id, + ) + .fetch_all(pool) + .await?; + + let (roles, groups) = result.into_iter().fold( + (Roles::empty(), Groups::empty()), + |(acc_roles, acc_groups), r| (acc_roles | r.roles.into(), acc_groups | r.groups.into()), + ); + + Ok((roles, groups)) + } + pub async fn get_members_from_user( pool: &PgPool, user_id: &uuid::Uuid, diff --git a/server/src/model/message.rs b/server/src/model/message.rs index a75c523..614eb0c 100644 --- a/server/src/model/message.rs +++ b/server/src/model/message.rs @@ -11,8 +11,8 @@ pub struct Message { pub title: String, pub content: String, pub channel: Channel, - pub member_groups: Option, - pub member_roles: Option, + pub member_groups: Groups, + pub member_roles: Roles, pub thumbnail_url: Option, } @@ -43,30 +43,57 @@ pub struct MessageCreate { pub scheduled_at: Option>, pub title: String, pub content: String, - pub channel: Channel, - pub member_groups: Option, - pub member_roles: Option, + pub channel: String, + pub member_groups: String, + pub member_roles: String, pub thumbnail_url: Option, } impl Message { - pub fn new(message_create: MessageCreate) -> Self { + pub fn new(message_create: MessageCreate) -> Result { let message_id = uuid::Uuid::new_v4(); let created_at = Utc::now(); - Self { + let channel: Channel = + bitflags::parser::from_str_strict(&message_create.channel).map_err(|_| { + crate::Error::BadRequest { + expected: String::from("Error while parsing channel"), + } + })?; + + let member_groups = if message_create.member_groups.is_empty() { + Ok(Groups::all()) + } else { + bitflags::parser::from_str_strict(&message_create.member_groups).map_err(|_| { + crate::Error::BadRequest { + expected: "Error while parsing groups".to_string(), + } + }) + }?; + + let member_roles = if message_create.member_roles.is_empty() { + Ok(Roles::all()) + } else { + bitflags::parser::from_str_strict(&message_create.member_roles).map_err(|_| { + crate::Error::BadRequest { + expected: "Error while parsing groups".to_string(), + } + }) + }?; + + Ok(Self { message_id, created_at, scheduled_at: message_create.scheduled_at, title: message_create.title, content: message_create.content, - channel: message_create.channel, + channel, thumbnail_url: message_create.thumbnail_url, - member_groups: message_create.member_groups, - member_roles: message_create.member_roles, + member_groups, + member_roles, status: MessageStatus::Pending, - } + }) } } @@ -83,8 +110,8 @@ impl From for Message { title: value.title, content: value.content, channel: value.channel, - member_groups: value.member_groups.into(), - member_roles: value.member_roles.into(), + member_groups: value.member_groups, + member_roles: value.member_roles, thumbnail_url: value.thumbnail_url, } } @@ -100,8 +127,8 @@ impl From for DbMessage { title: value.title, content: value.content, channel: value.channel, - member_groups: value.member_groups.into(), - member_roles: value.member_roles.into(), + member_groups: value.member_groups, + member_roles: value.member_roles, thumbnail_url: value.thumbnail_url, } } diff --git a/server/src/model/user.rs b/server/src/model/user.rs index 83912f1..24590f2 100644 --- a/server/src/model/user.rs +++ b/server/src/model/user.rs @@ -13,6 +13,7 @@ use crate::database::model::User as DbUser; use crate::database::model::UserMember as DbUserMember; use crate::util::convert_vec; +use super::member::Groups; use super::member::Roles; use super::Member; impl From for User { @@ -72,4 +73,8 @@ impl User { Ok(()) } + + pub async fn get_roles_groups(&self, pool: &PgPool) -> Result<(Roles, Groups), sqlx::Error> { + DbUserMember::get_roles_groups(pool, &self.id).await + } } diff --git a/server/src/routes/message.rs b/server/src/routes/message.rs index 290d208..1770da2 100644 --- a/server/src/routes/message.rs +++ b/server/src/routes/message.rs @@ -1,9 +1,5 @@ -use axum::{ - extract::State, - http::HeaderMap, - routing::post, - Json, Router, -}; +use axum::{extract::State, http::HeaderMap, routing::post, Json, Router}; +use bitflags::Flags; use serde::Deserialize; use crate::{ @@ -26,8 +22,8 @@ pub struct MessageCreateRequest { title: String, content: String, channel: String, - member_groups: Option, - member_roles: Option, + member_groups: String, + member_roles: String, } pub async fn message_create( @@ -40,39 +36,15 @@ pub async fn message_create( user.authorize(&state.pool, Some(Roles::ADMIN | Roles::MESSAGES), None) .await?; - let channel: Channel = bitflags::parser::from_str_strict(&request.channel).map_err(|_| { - crate::Error::BadRequest { - expected: String::from("Error while parsing channel"), - } - })?; - - let member_groups: Option = request - .member_groups - .map(|groups| { - bitflags::parser::from_str_strict(&groups).map_err(|_| crate::Error::BadRequest { - expected: String::from("Error while parsing member groups"), - }) - }) - .transpose()?; - - let member_roles: Option = request - .member_roles - .map(|roles| { - bitflags::parser::from_str_strict(&roles).map_err(|_| crate::Error::BadRequest { - expected: String::from("Error while parsing member roles"), - }) - }) - .transpose()?; - let db_message: DbMessage = Message::new(MessageCreate { title: request.title, content: request.content, - channel, - member_groups, - member_roles, + channel: request.channel, + member_groups: request.member_groups, + member_roles: request.member_roles, scheduled_at: None, thumbnail_url: None, - }) + })? .into(); let mut transaction = state.pool.begin().await?; diff --git a/server/src/routes/user.rs b/server/src/routes/user.rs index abb8a66..c7d0fd7 100644 --- a/server/src/routes/user.rs +++ b/server/src/routes/user.rs @@ -83,7 +83,9 @@ pub async fn get_messages( let user = get_user_from_header(&state.pool, &headers).await?; user.authorize(&state.pool, None, Some(user_id)).await?; - let messages = DbMessage::get(&state.pool, Channel::ALGEMEEN).await?; + let (roles, groups) = user.get_roles_groups(&state.pool).await?; + + let messages = DbMessage::get(&state.pool, Channel::ALGEMEEN, roles, groups).await?; Ok(Json(convert_vec(messages))) } diff --git a/server/src/util/cli.rs b/server/src/util/cli.rs index c5ed4ed..6321c5f 100644 --- a/server/src/util/cli.rs +++ b/server/src/util/cli.rs @@ -1,10 +1,7 @@ use clap::{Parser, Subcommand}; use sqlx::{Acquire, PgPool}; -use crate::model::{ - member::{Groups, Roles}, - Member, -}; +use crate::model::member::{Groups, Roles}; #[derive(Parser)] #[command(version, about, long_about = None)]