234 lines
7.4 KiB
Rust
234 lines
7.4 KiB
Rust
use crate::AppService;
|
|
use crate::error::AppError;
|
|
use chrono::Utc;
|
|
use models::projects::{ProjectWatch, project_audit_log, project_watch};
|
|
use models::users::user_email;
|
|
use sea_orm::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use session::Session;
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, utoipa::ToSchema)]
|
|
pub struct WatchUserInfo {
|
|
pub uid: Uuid,
|
|
pub username: String,
|
|
pub avatar_url: String,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn project_watch(&self, ctx: &Session, project_name: String) -> Result<(), AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let watch_exists = ProjectWatch::find()
|
|
.filter(project_watch::Column::User.eq(user_uid))
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.one(&self.db)
|
|
.await?;
|
|
|
|
if watch_exists.is_some() {
|
|
return Err(AppError::BadRequest(
|
|
"Already watching this project".to_string(),
|
|
));
|
|
}
|
|
|
|
ProjectWatch::insert(project_watch::ActiveModel {
|
|
id: Default::default(),
|
|
project: Set(project.id),
|
|
user: Set(user_uid),
|
|
notifications_enabled: Set(true),
|
|
created_at: Set(Utc::now()),
|
|
updated_at: Set(Utc::now()),
|
|
})
|
|
.exec(&self.db)
|
|
.await?;
|
|
|
|
let _ = self
|
|
.project_log_activity(
|
|
project.id,
|
|
None,
|
|
user_uid,
|
|
super::activity::ActivityLogParams {
|
|
event_type: "project_watch".to_string(),
|
|
title: format!("{} started watching the project", user_uid),
|
|
repo_id: None,
|
|
content: None,
|
|
event_id: None,
|
|
event_sub_id: None,
|
|
metadata: Some(serde_json::json!({
|
|
"project_name": project.name.clone(),
|
|
})),
|
|
is_private: false,
|
|
},
|
|
)
|
|
.await;
|
|
|
|
let log = project_audit_log::ActiveModel {
|
|
project: Set(project.id),
|
|
actor: Set(user_uid),
|
|
action: Set("project_watch".to_string()),
|
|
details: Set(Some(serde_json::json!({
|
|
"project_name": project.name.clone(),
|
|
}))),
|
|
created_at: Set(Utc::now()),
|
|
..Default::default()
|
|
};
|
|
log.insert(&self.db).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn project_unwatch(
|
|
&self,
|
|
ctx: &Session,
|
|
project_name: String,
|
|
) -> Result<(), AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let watch_exists = ProjectWatch::find()
|
|
.filter(project_watch::Column::User.eq(user_uid))
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.one(&self.db)
|
|
.await?;
|
|
|
|
if watch_exists.is_none() {
|
|
return Err(AppError::NotFound("Not watching this project".to_string()));
|
|
}
|
|
|
|
ProjectWatch::delete_many()
|
|
.filter(project_watch::Column::User.eq(user_uid))
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.exec(&self.db)
|
|
.await?;
|
|
|
|
let _ = self
|
|
.project_log_activity(
|
|
project.id,
|
|
None,
|
|
user_uid,
|
|
super::activity::ActivityLogParams {
|
|
event_type: "project_unwatch".to_string(),
|
|
title: format!("{} stopped watching the project", user_uid),
|
|
repo_id: None,
|
|
content: None,
|
|
event_id: None,
|
|
event_sub_id: None,
|
|
metadata: Some(serde_json::json!({
|
|
"project_name": project.name.clone(),
|
|
})),
|
|
is_private: false,
|
|
},
|
|
)
|
|
.await;
|
|
|
|
let log = project_audit_log::ActiveModel {
|
|
project: Set(project.id),
|
|
actor: Set(user_uid),
|
|
action: Set("project_unwatch".to_string()),
|
|
details: Set(Some(serde_json::json!({
|
|
"project_name": project.name.clone(),
|
|
}))),
|
|
created_at: Set(Utc::now()),
|
|
..Default::default()
|
|
};
|
|
log.insert(&self.db).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn project_is_watch(
|
|
&self,
|
|
ctx: &Session,
|
|
project_name: String,
|
|
) -> Result<bool, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let watch_exists = ProjectWatch::find()
|
|
.filter(project_watch::Column::User.eq(user_uid))
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.one(&self.db)
|
|
.await?;
|
|
|
|
Ok(watch_exists.is_some())
|
|
}
|
|
|
|
pub async fn project_watches(&self, project_name: String) -> Result<u64, AppError> {
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let watches = ProjectWatch::find()
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.count(&self.db)
|
|
.await?;
|
|
|
|
Ok(watches)
|
|
}
|
|
|
|
pub async fn project_watch_user_list(
|
|
&self,
|
|
project_name: String,
|
|
pager: crate::Pager,
|
|
) -> Result<Vec<WatchUserInfo>, AppError> {
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let watches = ProjectWatch::find()
|
|
.filter(project_watch::Column::Project.eq(project.id))
|
|
.order_by_desc(project_watch::Column::CreatedAt)
|
|
.limit(pager.par_page as u64)
|
|
.offset(((pager.page - 1) * pager.par_page) as u64)
|
|
.all(&self.db)
|
|
.await?;
|
|
|
|
let user_uids: Vec<Uuid> = watches.into_iter().map(|watch| watch.user).collect();
|
|
|
|
if user_uids.is_empty() {
|
|
return Ok(vec![]);
|
|
}
|
|
|
|
let users = models::users::user::Entity::find()
|
|
.filter(models::users::user::Column::Uid.is_in(user_uids))
|
|
.all(&self.db)
|
|
.await?
|
|
.into_iter()
|
|
.map(|u| WatchUserInfo {
|
|
uid: u.uid,
|
|
username: u.username,
|
|
avatar_url: u.avatar_url.unwrap_or_default(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(users)
|
|
}
|
|
|
|
pub async fn project_watch_user_emails(
|
|
&self,
|
|
project_uid: Uuid,
|
|
notify: bool,
|
|
) -> Result<Vec<String>, AppError> {
|
|
let watches = ProjectWatch::find()
|
|
.filter(project_watch::Column::Project.eq(project_uid))
|
|
.all(&self.db)
|
|
.await?
|
|
.into_iter()
|
|
.filter(|x| x.notifications_enabled == notify)
|
|
.collect::<Vec<_>>();
|
|
|
|
let user_uids: Vec<Uuid> = watches.into_iter().map(|watch| watch.user).collect();
|
|
|
|
if user_uids.is_empty() {
|
|
return Ok(vec![]);
|
|
}
|
|
|
|
let emails = user_email::Entity::find()
|
|
.filter(user_email::Column::User.is_in(user_uids))
|
|
.all(&self.db)
|
|
.await?
|
|
.into_iter()
|
|
.map(|u| u.email)
|
|
.collect();
|
|
|
|
Ok(emails)
|
|
}
|
|
}
|