Implement better way to define targets for messages

This commit is contained in:
xeovalyte 2025-02-28 12:12:08 +01:00
parent 0b8d6e2cc2
commit e5aace6e68
Signed by: xeovalyte
SSH Key Fingerprint: SHA256:GWI1hq+MNKR2UOcvk7n9tekASXT8vyazK7vDF9Xyciw
7 changed files with 101 additions and 60 deletions

View File

@ -62,15 +62,23 @@ impl Message {
Ok(()) Ok(())
} }
pub async fn get(pool: &PgPool, channel: Channel) -> Result<Vec<Self>, sqlx::Error> { pub async fn get(
pool: &PgPool,
channel: Channel,
member_roles: Roles,
member_groups: Groups,
) -> Result<Vec<Self>, sqlx::Error> {
let messages = sqlx::query_as!( let messages = sqlx::query_as!(
Self, Self,
" "
SELECT message_id, created_at, scheduled_at, status as \"status:MessageStatus\", title, content, channel, member_groups, member_roles, thumbnail_url FROM messages 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' 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) .fetch_all(pool)
.await?; .await?;

View File

@ -1,6 +1,6 @@
use sqlx::{PgPool, Postgres}; use sqlx::{PgPool, Postgres};
use crate::model::member::Roles; use crate::model::member::{Groups, Roles};
use super::Member as DbMember; use super::Member as DbMember;
@ -144,6 +144,36 @@ impl UserMember {
Ok(roles) 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( pub async fn get_members_from_user(
pool: &PgPool, pool: &PgPool,
user_id: &uuid::Uuid, user_id: &uuid::Uuid,

View File

@ -11,8 +11,8 @@ pub struct Message {
pub title: String, pub title: String,
pub content: String, pub content: String,
pub channel: Channel, pub channel: Channel,
pub member_groups: Option<Groups>, pub member_groups: Groups,
pub member_roles: Option<Roles>, pub member_roles: Roles,
pub thumbnail_url: Option<String>, pub thumbnail_url: Option<String>,
} }
@ -43,30 +43,57 @@ pub struct MessageCreate {
pub scheduled_at: Option<DateTime<Utc>>, pub scheduled_at: Option<DateTime<Utc>>,
pub title: String, pub title: String,
pub content: String, pub content: String,
pub channel: Channel, pub channel: String,
pub member_groups: Option<Groups>, pub member_groups: String,
pub member_roles: Option<Roles>, pub member_roles: String,
pub thumbnail_url: Option<String>, pub thumbnail_url: Option<String>,
} }
impl Message { impl Message {
pub fn new(message_create: MessageCreate) -> Self { pub fn new(message_create: MessageCreate) -> Result<Self, crate::Error> {
let message_id = uuid::Uuid::new_v4(); let message_id = uuid::Uuid::new_v4();
let created_at = Utc::now(); 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, message_id,
created_at, created_at,
scheduled_at: message_create.scheduled_at, scheduled_at: message_create.scheduled_at,
title: message_create.title, title: message_create.title,
content: message_create.content, content: message_create.content,
channel: message_create.channel, channel,
thumbnail_url: message_create.thumbnail_url, thumbnail_url: message_create.thumbnail_url,
member_groups: message_create.member_groups, member_groups,
member_roles: message_create.member_roles, member_roles,
status: MessageStatus::Pending, status: MessageStatus::Pending,
} })
} }
} }
@ -83,8 +110,8 @@ impl From<DbMessage> for Message {
title: value.title, title: value.title,
content: value.content, content: value.content,
channel: value.channel, channel: value.channel,
member_groups: value.member_groups.into(), member_groups: value.member_groups,
member_roles: value.member_roles.into(), member_roles: value.member_roles,
thumbnail_url: value.thumbnail_url, thumbnail_url: value.thumbnail_url,
} }
} }
@ -100,8 +127,8 @@ impl From<Message> for DbMessage {
title: value.title, title: value.title,
content: value.content, content: value.content,
channel: value.channel, channel: value.channel,
member_groups: value.member_groups.into(), member_groups: value.member_groups,
member_roles: value.member_roles.into(), member_roles: value.member_roles,
thumbnail_url: value.thumbnail_url, thumbnail_url: value.thumbnail_url,
} }
} }

View File

@ -13,6 +13,7 @@ use crate::database::model::User as DbUser;
use crate::database::model::UserMember as DbUserMember; use crate::database::model::UserMember as DbUserMember;
use crate::util::convert_vec; use crate::util::convert_vec;
use super::member::Groups;
use super::member::Roles; use super::member::Roles;
use super::Member; use super::Member;
impl From<DbUser> for User { impl From<DbUser> for User {
@ -72,4 +73,8 @@ impl User {
Ok(()) Ok(())
} }
pub async fn get_roles_groups(&self, pool: &PgPool) -> Result<(Roles, Groups), sqlx::Error> {
DbUserMember::get_roles_groups(pool, &self.id).await
}
} }

View File

@ -1,9 +1,5 @@
use axum::{ use axum::{extract::State, http::HeaderMap, routing::post, Json, Router};
extract::State, use bitflags::Flags;
http::HeaderMap,
routing::post,
Json, Router,
};
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
@ -26,8 +22,8 @@ pub struct MessageCreateRequest {
title: String, title: String,
content: String, content: String,
channel: String, channel: String,
member_groups: Option<String>, member_groups: String,
member_roles: Option<String>, member_roles: String,
} }
pub async fn message_create( pub async fn message_create(
@ -40,39 +36,15 @@ pub async fn message_create(
user.authorize(&state.pool, Some(Roles::ADMIN | Roles::MESSAGES), None) user.authorize(&state.pool, Some(Roles::ADMIN | Roles::MESSAGES), None)
.await?; .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<Groups> = 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<Roles> = 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 { let db_message: DbMessage = Message::new(MessageCreate {
title: request.title, title: request.title,
content: request.content, content: request.content,
channel, channel: request.channel,
member_groups, member_groups: request.member_groups,
member_roles, member_roles: request.member_roles,
scheduled_at: None, scheduled_at: None,
thumbnail_url: None, thumbnail_url: None,
}) })?
.into(); .into();
let mut transaction = state.pool.begin().await?; let mut transaction = state.pool.begin().await?;

View File

@ -83,7 +83,9 @@ pub async fn get_messages(
let user = get_user_from_header(&state.pool, &headers).await?; let user = get_user_from_header(&state.pool, &headers).await?;
user.authorize(&state.pool, None, Some(user_id)).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))) Ok(Json(convert_vec(messages)))
} }

View File

@ -1,10 +1,7 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use sqlx::{Acquire, PgPool}; use sqlx::{Acquire, PgPool};
use crate::model::{ use crate::model::member::{Groups, Roles};
member::{Groups, Roles},
Member,
};
#[derive(Parser)] #[derive(Parser)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]