279 lines
9.6 KiB
Rust
279 lines
9.6 KiB
Rust
use crate::AppService;
|
|
use crate::error::AppError;
|
|
use chrono::{DateTime, Utc};
|
|
use models::projects::{project_members, project_message_favorite};
|
|
use models::rooms::{room, room_message};
|
|
use sea_orm::sea_query::Expr;
|
|
use sea_orm::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use session::Session;
|
|
use utoipa::{IntoParams, ToSchema};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema, IntoParams)]
|
|
pub struct ProjectMessageFavoriteQuery {
|
|
pub page: Option<u64>,
|
|
pub per_page: Option<u64>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
|
|
pub struct ProjectMessageFavoriteItem {
|
|
pub uid: Uuid,
|
|
pub project_uid: Uuid,
|
|
pub room_id: Uuid,
|
|
pub room_name: String,
|
|
pub message_id: Uuid,
|
|
pub sender_id: Option<Uuid>,
|
|
pub sender_type: String,
|
|
pub display_name: Option<String>,
|
|
pub content: String,
|
|
pub content_type: String,
|
|
pub send_at: DateTime<Utc>,
|
|
pub favorited_at: DateTime<Utc>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
|
|
pub struct ProjectMessageFavoriteResponse {
|
|
pub page: u64,
|
|
pub per_page: u64,
|
|
pub total: u64,
|
|
pub list: Vec<ProjectMessageFavoriteItem>,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn project_message_favorites(
|
|
&self,
|
|
ctx: &Session,
|
|
project_name: String,
|
|
query: ProjectMessageFavoriteQuery,
|
|
) -> Result<ProjectMessageFavoriteResponse, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
self.require_project_member(project.id, user_uid).await?;
|
|
|
|
let page = std::cmp::max(query.page.unwrap_or(1), 1);
|
|
let per_page = std::cmp::min(std::cmp::max(query.per_page.unwrap_or(20), 1), 100);
|
|
|
|
let base = project_message_favorite::Entity::find()
|
|
.filter(project_message_favorite::Column::Project.eq(project.id))
|
|
.filter(project_message_favorite::Column::User.eq(user_uid));
|
|
let total = base.clone().count(&self.db).await?;
|
|
|
|
let rows = base
|
|
.join(
|
|
JoinType::InnerJoin,
|
|
project_message_favorite::Entity::belongs_to(room_message::Entity)
|
|
.from(project_message_favorite::Column::Message)
|
|
.to(room_message::Column::Id)
|
|
.into(),
|
|
)
|
|
.join(
|
|
JoinType::InnerJoin,
|
|
project_message_favorite::Entity::belongs_to(room::Entity)
|
|
.from(project_message_favorite::Column::Room)
|
|
.to(room::Column::Id)
|
|
.into(),
|
|
)
|
|
.filter(room_message::Column::Revoked.is_null())
|
|
.order_by_desc(project_message_favorite::Column::CreatedAt)
|
|
.select_only()
|
|
.column_as(project_message_favorite::Column::Uid, "uid")
|
|
.column_as(project_message_favorite::Column::Project, "project_uid")
|
|
.column_as(project_message_favorite::Column::Room, "room_id")
|
|
.column_as(room::Column::RoomName, "room_name")
|
|
.column_as(project_message_favorite::Column::Message, "message_id")
|
|
.column_as(room_message::Column::SenderId, "sender_id")
|
|
.column_as(Expr::cust("room_message.sender_type::text"), "sender_type")
|
|
.column_as(room_message::Column::Content, "content")
|
|
.column_as(
|
|
Expr::cust("room_message.content_type::text"),
|
|
"content_type",
|
|
)
|
|
.column_as(room_message::Column::SendAt, "send_at")
|
|
.column_as(project_message_favorite::Column::CreatedAt, "favorited_at")
|
|
.column_as(
|
|
Expr::cust(
|
|
"coalesce(room_message.sender_id::text, room_message.sender_type::text)",
|
|
),
|
|
"display_name",
|
|
)
|
|
.limit(per_page)
|
|
.offset((page - 1) * per_page)
|
|
.into_tuple::<(
|
|
Uuid,
|
|
Uuid,
|
|
Uuid,
|
|
String,
|
|
Uuid,
|
|
Option<Uuid>,
|
|
String,
|
|
String,
|
|
String,
|
|
DateTime<Utc>,
|
|
DateTime<Utc>,
|
|
Option<String>,
|
|
)>()
|
|
.all(&self.db)
|
|
.await?;
|
|
|
|
let list = rows
|
|
.into_iter()
|
|
.map(
|
|
|(
|
|
uid,
|
|
project_uid,
|
|
room_id,
|
|
room_name,
|
|
message_id,
|
|
sender_id,
|
|
sender_type,
|
|
content,
|
|
content_type,
|
|
send_at,
|
|
favorited_at,
|
|
display_name,
|
|
)| ProjectMessageFavoriteItem {
|
|
uid,
|
|
project_uid,
|
|
room_id,
|
|
room_name,
|
|
message_id,
|
|
sender_id,
|
|
sender_type,
|
|
display_name,
|
|
content,
|
|
content_type,
|
|
send_at,
|
|
favorited_at,
|
|
},
|
|
)
|
|
.collect();
|
|
|
|
Ok(ProjectMessageFavoriteResponse {
|
|
page,
|
|
per_page,
|
|
total,
|
|
list,
|
|
})
|
|
}
|
|
|
|
pub async fn project_message_favorite_add(
|
|
&self,
|
|
ctx: &Session,
|
|
project_name: String,
|
|
message_id: Uuid,
|
|
) -> Result<ProjectMessageFavoriteItem, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self
|
|
.utils_find_project_by_name(project_name.clone())
|
|
.await?;
|
|
self.require_project_member(project.id, user_uid).await?;
|
|
|
|
let message = room_message::Entity::find_by_id(message_id)
|
|
.one(&self.db)
|
|
.await?
|
|
.ok_or_else(|| AppError::NotFound("message".to_string()))?;
|
|
if message.revoked.is_some() {
|
|
return Err(AppError::NotFound("message".to_string()));
|
|
}
|
|
|
|
let room = room::Entity::find_by_id(message.room)
|
|
.one(&self.db)
|
|
.await?
|
|
.ok_or_else(|| AppError::NotFound("room".to_string()))?;
|
|
if room.project != project.id {
|
|
return Err(AppError::NotFound("message".to_string()));
|
|
}
|
|
|
|
if let Some(existing) = project_message_favorite::Entity::find()
|
|
.filter(project_message_favorite::Column::User.eq(user_uid))
|
|
.filter(project_message_favorite::Column::Message.eq(message.id))
|
|
.one(&self.db)
|
|
.await?
|
|
{
|
|
return Ok(ProjectMessageFavoriteItem {
|
|
uid: existing.uid,
|
|
project_uid: existing.project,
|
|
room_id: existing.room,
|
|
room_name: room.room_name,
|
|
message_id: existing.message,
|
|
sender_id: message.sender_id,
|
|
sender_type: message.sender_type.to_string(),
|
|
display_name: message
|
|
.sender_id
|
|
.map(|id| id.to_string())
|
|
.or_else(|| Some(message.sender_type.to_string())),
|
|
content: message.content,
|
|
content_type: message.content_type.to_string(),
|
|
send_at: message.send_at,
|
|
favorited_at: existing.created_at,
|
|
});
|
|
}
|
|
|
|
let created = project_message_favorite::ActiveModel {
|
|
uid: Set(Uuid::new_v4()),
|
|
project: Set(project.id),
|
|
room: Set(message.room),
|
|
message: Set(message.id),
|
|
user: Set(user_uid),
|
|
created_at: Set(Utc::now()),
|
|
}
|
|
.insert(&self.db)
|
|
.await?;
|
|
|
|
Ok(ProjectMessageFavoriteItem {
|
|
uid: created.uid,
|
|
project_uid: created.project,
|
|
room_id: created.room,
|
|
room_name: room.room_name,
|
|
message_id: created.message,
|
|
sender_id: message.sender_id,
|
|
sender_type: message.sender_type.to_string(),
|
|
display_name: message
|
|
.sender_id
|
|
.map(|id| id.to_string())
|
|
.or_else(|| Some(message.sender_type.to_string())),
|
|
content: message.content,
|
|
content_type: message.content_type.to_string(),
|
|
send_at: message.send_at,
|
|
favorited_at: created.created_at,
|
|
})
|
|
}
|
|
|
|
pub async fn project_message_favorite_remove(
|
|
&self,
|
|
ctx: &Session,
|
|
project_name: String,
|
|
message_id: Uuid,
|
|
) -> Result<(), AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
self.require_project_member(project.id, user_uid).await?;
|
|
|
|
project_message_favorite::Entity::delete_many()
|
|
.filter(project_message_favorite::Column::Project.eq(project.id))
|
|
.filter(project_message_favorite::Column::User.eq(user_uid))
|
|
.filter(project_message_favorite::Column::Message.eq(message_id))
|
|
.exec(&self.db)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn require_project_member(
|
|
&self,
|
|
project_id: Uuid,
|
|
user_id: Uuid,
|
|
) -> Result<(), AppError> {
|
|
let member = project_members::Entity::find()
|
|
.filter(project_members::Column::Project.eq(project_id))
|
|
.filter(project_members::Column::User.eq(user_id))
|
|
.one(&self.db)
|
|
.await?;
|
|
if member.is_some() {
|
|
Ok(())
|
|
} else {
|
|
Err(AppError::NoPower)
|
|
}
|
|
}
|
|
}
|