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(())
}
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!(
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?;

View File

@ -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,

View File

@ -11,8 +11,8 @@ pub struct Message {
pub title: String,
pub content: String,
pub channel: Channel,
pub member_groups: Option<Groups>,
pub member_roles: Option<Roles>,
pub member_groups: Groups,
pub member_roles: Roles,
pub thumbnail_url: Option<String>,
}
@ -43,30 +43,57 @@ pub struct MessageCreate {
pub scheduled_at: Option<DateTime<Utc>>,
pub title: String,
pub content: String,
pub channel: Channel,
pub member_groups: Option<Groups>,
pub member_roles: Option<Roles>,
pub channel: String,
pub member_groups: String,
pub member_roles: String,
pub thumbnail_url: Option<String>,
}
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 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<DbMessage> 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<Message> 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,
}
}

View File

@ -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<DbUser> 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
}
}

View File

@ -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<String>,
member_roles: Option<String>,
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<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 {
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?;

View File

@ -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)))
}

View File

@ -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)]