Skip to content
Clone
a06673b
100 lines 3.4 KB Rust
use db::conn::sea_orm::*;
use db::issue::issue_reactions as reaction_entity;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::error::{IssueError, IssueResult};
use crate::features::IssueService;
use crate::features::issue::usecase::load_issue;
use super::super::{CreateReactionOption, ReactionView};
use super::helpers::{ensure_issue_visible, require_authenticated};
pub async fn create_issue_reaction(
svc: &IssueService,
actor: Uuid,
channel_id: Uuid,
issue_id: Uuid,
input: CreateReactionOption,
) -> IssueResult<ReactionView> {
require_authenticated(actor)?;
validate_emoji(svc, &input.emoji)?;
ensure_issue_visible(svc, channel_id, issue_id).await?;
let db = svc.db.writer();
let id = Uuid::new_v4();
let active: reaction_entity::ActiveModel = reaction_entity::ActiveModel::builder()
.set_id(id)
.set_issue_id(Some(issue_id))
.set_comment_id(None)
.set_user_id(actor)
.set_emoji(input.emoji)
.set_created_at(OffsetDateTime::now_utc())
.into();
match reaction_entity::Entity::insert(active)
.on_conflict_do_nothing()
.exec(&db)
.await?
{
TryInsertResult::Inserted(_) | TryInsertResult::Empty => {}
TryInsertResult::Conflicted => {
return Err(IssueError::Conflict("reaction already exists".into()));
}
}
let saved = reaction_entity::Entity::find_by_id(id)
.one(&db)
.await?
.ok_or_else(|| IssueError::Internal("reaction not found after insert".into()))?;
Ok(ReactionView::from(saved))
}
pub async fn create_comment_reaction(
svc: &IssueService,
actor: Uuid,
channel_id: Uuid,
issue_id: Uuid,
comment_id: Uuid,
input: CreateReactionOption,
) -> IssueResult<ReactionView> {
require_authenticated(actor)?;
validate_emoji(svc, &input.emoji)?;
load_issue(svc, channel_id, issue_id).await?;
crate::features::comment::usecase::require_authenticated(actor)?;
let db = svc.db.reader();
let _c = db::issue::comment::Entity::find_by_id(comment_id)
.filter(db::issue::comment::COLUMN.issue_id.eq(issue_id))
.one(&db)
.await?
.ok_or_else(|| IssueError::NotFound(format!("comment {comment_id}")))?;
let db = svc.db.writer();
let id = Uuid::new_v4();
let active: reaction_entity::ActiveModel = reaction_entity::ActiveModel::builder()
.set_id(id)
.set_issue_id(None)
.set_comment_id(Some(comment_id))
.set_user_id(actor)
.set_emoji(input.emoji)
.set_created_at(OffsetDateTime::now_utc())
.into();
match reaction_entity::Entity::insert(active)
.on_conflict_do_nothing()
.exec(&db)
.await?
{
TryInsertResult::Inserted(_) | TryInsertResult::Empty => {}
TryInsertResult::Conflicted => {
return Err(IssueError::Conflict("reaction already exists".into()));
}
}
let saved = reaction_entity::Entity::find_by_id(id)
.one(&db)
.await?
.ok_or_else(|| IssueError::Internal("reaction not found after insert".into()))?;
Ok(ReactionView::from(saved))
}
fn validate_emoji(svc: &IssueService, emoji: &str) -> IssueResult<()> {
if emoji.trim().is_empty() || emoji.len() > svc.config.max_reaction_emoji_len {
return Err(IssueError::BadRequest("invalid emoji".into()));
}
Ok(())
}