From 9eb77ab98bb3fa91b58e334bc23bda46474f87fb Mon Sep 17 00:00:00 2001 From: zhenyi <434836402@qq.com> Date: Wed, 10 Jun 2026 18:49:37 +0800 Subject: [PATCH] refactor(models): update data models and remove deprecated IM entities - Update channel, notification, PR, repo, user, workspace models - Remove deleted IM models: articles, channel follows, message attachments/bookmarks/drafts/edit history/embeds/mentions/pins/ polls/reactions/threads, saved messages, thread read states - Add new PR models: review requests, templates - Add repo release assets model - Add base_info module for API detail responses --- models/base_info.rs | 330 ++++++++++++++++++ models/channels/article_comments.rs | 18 - models/channels/article_cross_posts.rs | 22 -- models/channels/article_reactions.rs | 14 - models/channels/articles.rs | 35 -- models/channels/channel.rs | 64 +++- models/channels/channel_categories.rs | 2 +- models/channels/channel_follows.rs | 23 -- models/channels/channel_members.rs | 2 +- .../channels/channel_permission_overwrites.rs | 6 +- models/channels/message.rs | 23 -- models/channels/message_attachments.rs | 21 -- models/channels/message_bookmarks.rs | 14 - models/channels/message_drafts.rs | 17 - models/channels/message_edit_history.rs | 13 - models/channels/message_embeds.rs | 34 -- models/channels/message_mentions.rs | 14 - models/channels/message_pins.rs | 12 - models/channels/message_poll_options.rs | 16 - models/channels/message_poll_votes.rs | 13 - models/channels/message_polls.rs | 22 -- models/channels/message_reactions.rs | 13 - models/channels/message_threads.rs | 27 -- models/channels/mod.rs | 42 +-- models/channels/saved_messages.rs | 13 - models/channels/thread_read_states.rs | 14 - models/issues/issue.rs | 46 +++ models/issues/issue_comments.rs | 28 ++ models/issues/mod.rs | 4 +- models/mod.rs | 1 + models/notifications/mod.rs | 2 +- models/notifications/notification.rs | 65 +++- models/notifications/notification_blocks.rs | 2 +- .../notifications/notification_deliveries.rs | 2 +- .../notification_subscriptions.rs | 2 +- .../notifications/notification_templates.rs | 2 +- models/prs/mod.rs | 8 +- models/prs/pr_review.rs | 32 ++ models/prs/pr_review_requests.rs | 11 + models/prs/pr_templates.rs | 17 + models/prs/pull_request.rs | 58 +++ models/repos/mod.rs | 4 +- models/repos/repo.rs | 88 +++++ models/repos/repo_release_assets.rs | 19 + models/users/user.rs | 4 + models/users/user_block.rs | 2 +- models/users/user_follow.rs | 2 +- models/users/user_presence.rs | 2 +- models/workspaces/mod.rs | 2 +- models/workspaces/workspace.rs | 40 +++ 50 files changed, 827 insertions(+), 440 deletions(-) create mode 100644 models/base_info.rs delete mode 100644 models/channels/article_comments.rs delete mode 100644 models/channels/article_cross_posts.rs delete mode 100644 models/channels/article_reactions.rs delete mode 100644 models/channels/articles.rs delete mode 100644 models/channels/channel_follows.rs delete mode 100644 models/channels/message.rs delete mode 100644 models/channels/message_attachments.rs delete mode 100644 models/channels/message_bookmarks.rs delete mode 100644 models/channels/message_drafts.rs delete mode 100644 models/channels/message_edit_history.rs delete mode 100644 models/channels/message_embeds.rs delete mode 100644 models/channels/message_mentions.rs delete mode 100644 models/channels/message_pins.rs delete mode 100644 models/channels/message_poll_options.rs delete mode 100644 models/channels/message_poll_votes.rs delete mode 100644 models/channels/message_polls.rs delete mode 100644 models/channels/message_reactions.rs delete mode 100644 models/channels/message_threads.rs delete mode 100644 models/channels/saved_messages.rs delete mode 100644 models/channels/thread_read_states.rs create mode 100644 models/prs/pr_review_requests.rs create mode 100644 models/prs/pr_templates.rs create mode 100644 models/repos/repo_release_assets.rs diff --git a/models/base_info.rs b/models/base_info.rs new file mode 100644 index 0000000..62fe160 --- /dev/null +++ b/models/base_info.rs @@ -0,0 +1,330 @@ +//! BaseInfo structs — stable, minimal projections of core entities for API/WS responses. +//! +//! Every raw UUID foreign key in API / WebSocket responses must be expanded +//! to its corresponding `*BaseInfo` object so frontend consumers never +//! receive bare identifiers. +//! +//! Batch resolvers are provided to avoid N+1 queries when enriching +//! collections of entities. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::error::AppError; +use crate::models::common::{ChannelType, State, Visibility}; +use crate::models::db::AppDatabase; + +// Section: BaseInfo structs + +#[derive(Debug, Clone, Default, Serialize, Deserialize, utoipa::ToSchema)] +pub struct UserBaseInfo { + pub id: Uuid, + pub username: String, + pub display_name: Option, + pub avatar_url: Option, + pub is_bot: bool, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, utoipa::ToSchema)] +pub struct WorkspaceBaseInfo { + pub id: Uuid, + pub name: String, + pub avatar_url: Option, + pub visibility: Visibility, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct RepoBaseInfo { + pub id: Uuid, + pub name: String, + pub workspace_id: Uuid, + pub visibility: Visibility, + pub is_fork: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct ChannelBaseInfo { + pub id: Uuid, + pub name: String, + pub channel_type: ChannelType, + pub workspace_id: Uuid, + pub archived: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct IssueBaseInfo { + pub id: Uuid, + pub number: i64, + pub title: String, + pub state: State, + pub workspace_id: Uuid, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct PullRequestBaseInfo { + pub id: Uuid, + pub number: i64, + pub title: String, + pub state: State, + pub repo_id: Uuid, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct WikiPageBaseInfo { + pub id: Uuid, + pub title: String, + pub slug: String, + pub repo_id: Uuid, +} + +// Section: DB row structs for batch queries + +#[derive(Debug, sqlx::FromRow)] +struct UserBaseInfoRow { + id: Uuid, + username: String, + display_name: Option, + avatar_url: Option, + is_bot: bool, +} + +impl From for UserBaseInfo { + fn from(r: UserBaseInfoRow) -> Self { + UserBaseInfo { + id: r.id, + username: r.username, + display_name: r.display_name, + avatar_url: r.avatar_url, + is_bot: r.is_bot, + } + } +} + +#[derive(Debug, sqlx::FromRow)] +struct WorkspaceBaseInfoRow { + id: Uuid, + name: String, + avatar_url: Option, + visibility: Visibility, +} + +impl From for WorkspaceBaseInfo { + fn from(r: WorkspaceBaseInfoRow) -> Self { + WorkspaceBaseInfo { + id: r.id, + name: r.name, + avatar_url: r.avatar_url, + visibility: r.visibility, + } + } +} + +#[derive(Debug, sqlx::FromRow)] +struct RepoBaseInfoRow { + id: Uuid, + name: String, + workspace_id: Uuid, + visibility: Visibility, + is_fork: bool, +} + +impl From for RepoBaseInfo { + fn from(r: RepoBaseInfoRow) -> Self { + RepoBaseInfo { + id: r.id, + name: r.name, + workspace_id: r.workspace_id, + visibility: r.visibility, + is_fork: r.is_fork, + } + } +} + +#[derive(Debug, sqlx::FromRow)] +struct ChannelBaseInfoRow { + id: Uuid, + name: String, + channel_type: ChannelType, + workspace_id: Uuid, + archived: bool, +} + +impl From for ChannelBaseInfo { + fn from(r: ChannelBaseInfoRow) -> Self { + ChannelBaseInfo { + id: r.id, + name: r.name, + channel_type: r.channel_type, + workspace_id: r.workspace_id, + archived: r.archived, + } + } +} + +#[derive(Debug, sqlx::FromRow)] +struct IssueBaseInfoRow { + id: Uuid, + number: i64, + title: String, + state: State, + workspace_id: Uuid, +} + +impl From for IssueBaseInfo { + fn from(r: IssueBaseInfoRow) -> Self { + IssueBaseInfo { + id: r.id, + number: r.number, + title: r.title, + state: r.state, + workspace_id: r.workspace_id, + } + } +} + +#[derive(Debug, sqlx::FromRow)] +struct PullRequestBaseInfoRow { + id: Uuid, + number: i64, + title: String, + state: State, + repo_id: Uuid, +} + +impl From for PullRequestBaseInfo { + fn from(r: PullRequestBaseInfoRow) -> Self { + PullRequestBaseInfo { + id: r.id, + number: r.number, + title: r.title, + state: r.state, + repo_id: r.repo_id, + } + } +} + +impl UserBaseInfo { + pub fn placeholder(id: Uuid) -> Self { + Self { + id, + username: "unknown".into(), + display_name: Some("Unknown User".into()), + avatar_url: None, + is_bot: false, + } + } +} + +// Section: Batch resolvers + +/// Resolve multiple users to `UserBaseInfo`. Always do a single +/// `SELECT … WHERE id = ANY($1)` to avoid N+1. +pub async fn resolve_users( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, UserBaseInfoRow>( + r#"SELECT id, username, display_name, avatar_url, is_bot + FROM "user" WHERE id = ANY($1) AND deleted_at IS NULL"#, + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} + +/// Resolve multiple workspaces to `WorkspaceBaseInfo`. +pub async fn resolve_workspaces( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, WorkspaceBaseInfoRow>( + "SELECT id, name, avatar_url, visibility FROM workspace WHERE id = ANY($1) AND deleted_at IS NULL", + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} + +/// Resolve multiple repos to `RepoBaseInfo`. +pub async fn resolve_repos( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, RepoBaseInfoRow>( + "SELECT id, name, workspace_id, visibility, is_fork FROM repo WHERE id = ANY($1) AND deleted_at IS NULL", + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} + +/// Resolve multiple channels to `ChannelBaseInfo`. +pub async fn resolve_channels( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, ChannelBaseInfoRow>( + "SELECT id, name, channel_type, workspace_id, archived FROM channel WHERE id = ANY($1) AND deleted_at IS NULL", + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} + +/// Resolve multiple issues to `IssueBaseInfo`. +pub async fn resolve_issues( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, IssueBaseInfoRow>( + "SELECT id, number, title, state, workspace_id FROM issue WHERE id = ANY($1) AND deleted_at IS NULL", + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} + +/// Resolve multiple pull requests to `PullRequestBaseInfo`. +pub async fn resolve_pull_requests( + db: &AppDatabase, + ids: &[Uuid], +) -> Result, AppError> { + if ids.is_empty() { + return Ok(HashMap::new()); + } + let rows = sqlx::query_as::<_, PullRequestBaseInfoRow>( + "SELECT id, number, title, state, repo_id FROM pull_request WHERE id = ANY($1) AND deleted_at IS NULL", + ) + .bind(ids) + .fetch_all(db.reader()) + .await + .map_err(AppError::Database)?; + Ok(rows.into_iter().map(|r| (r.id, r.into())).collect()) +} diff --git a/models/channels/article_comments.rs b/models/channels/article_comments.rs deleted file mode 100644 index da67e7f..0000000 --- a/models/channels/article_comments.rs +++ /dev/null @@ -1,18 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Discussion comment on an article (similar to blog comments). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct ArticleComment { - pub id: Uuid, - pub article_id: Uuid, - pub channel_id: Uuid, - pub author_id: Uuid, - pub parent_comment_id: Option, - pub body: String, - pub edited_at: Option>, - pub deleted_at: Option>, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/article_cross_posts.rs b/models/channels/article_cross_posts.rs deleted file mode 100644 index 62ef5a5..0000000 --- a/models/channels/article_cross_posts.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::models::common::Status; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Tracks a single cross-post delivery when an article is published -/// to a follower channel/workspace. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct ArticleCrossPost { - pub id: Uuid, - pub article_id: Uuid, - pub follow_id: Uuid, - pub target_workspace_id: Uuid, - pub target_channel_id: Option, - pub status: Status, - pub attempts: i32, - pub last_error: Option, - pub sent_at: Option>, - pub delivered_at: Option>, - pub failed_at: Option>, - pub created_at: DateTime, -} diff --git a/models/channels/article_reactions.rs b/models/channels/article_reactions.rs deleted file mode 100644 index 19dfc6d..0000000 --- a/models/channels/article_reactions.rs +++ /dev/null @@ -1,14 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Reaction on an article (emoji reactions, separate from message reactions). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct ArticleReaction { - pub id: Uuid, - pub article_id: Uuid, - pub channel_id: Uuid, - pub user_id: Uuid, - pub content: String, - pub created_at: DateTime, -} diff --git a/models/channels/articles.rs b/models/channels/articles.rs deleted file mode 100644 index 82edfa4..0000000 --- a/models/channels/articles.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::models::common::{ArticleStatus, JsonValue, Visibility}; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Long-form article for announcement/news channels. -/// Unlike a plain Message, an article has a title, cover image, -/// publish lifecycle, and can be cross-posted to followers. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct Article { - pub id: Uuid, - pub channel_id: Uuid, - pub author_id: Uuid, - pub title: String, - pub slug: String, - pub summary: Option, - pub body: String, - pub cover_image_url: Option, - pub status: ArticleStatus, - pub visibility: Visibility, - pub tags: Vec, - pub published_at: Option>, - pub published_by: Option, - pub scheduled_at: Option>, - pub unpublished_at: Option>, - pub views_count: i64, - pub comments_count: i64, - pub reactions_count: i64, - pub cross_posted: bool, - pub cross_posted_from: Option, - pub metadata: Option, - pub created_at: DateTime, - pub updated_at: DateTime, - pub deleted_at: Option>, -} diff --git a/models/channels/channel.rs b/models/channels/channel.rs index acec078..8141f4f 100644 --- a/models/channels/channel.rs +++ b/models/channels/channel.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use crate::models::common::{ ChannelKind, ChannelType, ForumLayout, ForumSortOrder, JsonValue, Visibility, }; @@ -5,7 +6,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct Channel { pub id: Uuid, pub workspace_id: Uuid, @@ -41,3 +42,64 @@ pub struct Channel { pub updated_at: DateTime, pub deleted_at: Option>, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct ChannelDetail { + pub id: Uuid, + pub workspace_id: Uuid, + pub repo_id: Option, + pub category_id: Option, + pub creator: UserBaseInfo, + pub name: String, + pub topic: Option, + pub description: Option, + pub channel_type: ChannelType, + pub channel_kind: ChannelKind, + pub visibility: Visibility, + pub position: Option, + pub nsfw: bool, + pub archived: bool, + pub read_only: bool, + pub bitrate: Option, + pub user_limit: Option, + pub rtc_region: Option, + pub parent_channel_id: Option, + pub last_message_id: Option, + pub last_message_at: Option>, + pub archived_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl Channel { + pub fn into_detail(self, creator: UserBaseInfo) -> ChannelDetail { + ChannelDetail { + id: self.id, + workspace_id: self.workspace_id, + repo_id: self.repo_id, + category_id: self.category_id, + creator, + name: self.name, + topic: self.topic, + description: self.description, + channel_type: self.channel_type, + channel_kind: self.channel_kind, + visibility: self.visibility, + position: self.position, + nsfw: self.nsfw, + archived: self.archived, + read_only: self.read_only, + bitrate: self.bitrate, + user_limit: self.user_limit, + rtc_region: self.rtc_region, + parent_channel_id: self.parent_channel_id, + last_message_id: self.last_message_id, + last_message_at: self.last_message_at, + archived_at: self.archived_at, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +} diff --git a/models/channels/channel_categories.rs b/models/channels/channel_categories.rs index 8ca1405..cbe6f96 100644 --- a/models/channels/channel_categories.rs +++ b/models/channels/channel_categories.rs @@ -2,7 +2,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct ChannelCategory { pub id: Uuid, pub workspace_id: Uuid, diff --git a/models/channels/channel_follows.rs b/models/channels/channel_follows.rs deleted file mode 100644 index 3be70ed..0000000 --- a/models/channels/channel_follows.rs +++ /dev/null @@ -1,23 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Follow relationship on an announcement channel. -/// Allows another workspace or channel to receive cross-posts -/// when articles are published. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct ChannelFollow { - pub id: Uuid, - pub source_channel_id: Uuid, - pub target_workspace_id: Uuid, - pub target_channel_id: Option, - pub webhook_url: Option, - pub webhook_secret_ciphertext: Option, - pub enabled: bool, - pub followed_by: Uuid, - pub unfollowed_at: Option>, - pub last_delivery_at: Option>, - pub last_delivery_status: Option, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/channel_members.rs b/models/channels/channel_members.rs index e3588f4..6f96fe1 100644 --- a/models/channels/channel_members.rs +++ b/models/channels/channel_members.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct ChannelMember { pub id: Uuid, pub channel_id: Uuid, diff --git a/models/channels/channel_permission_overwrites.rs b/models/channels/channel_permission_overwrites.rs index 72746d2..6ac83a7 100644 --- a/models/channels/channel_permission_overwrites.rs +++ b/models/channels/channel_permission_overwrites.rs @@ -1,4 +1,4 @@ -use crate::models::common::{OverwriteTarget, Permission}; +use crate::models::common::OverwriteTarget; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -9,8 +9,8 @@ pub struct ChannelPermissionOverwrite { pub channel_id: Uuid, pub target_type: OverwriteTarget, pub target_id: Uuid, - pub allow: Vec, - pub deny: Vec, + pub allow: Vec, + pub deny: Vec, pub created_by: Uuid, pub created_at: DateTime, pub updated_at: DateTime, diff --git a/models/channels/message.rs b/models/channels/message.rs deleted file mode 100644 index 737bf24..0000000 --- a/models/channels/message.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::models::common::{JsonValue, MessageType}; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct Message { - pub id: Uuid, - pub channel_id: Uuid, - pub author_id: Uuid, - pub thread_id: Option, - pub reply_to_message_id: Option, - pub seq: i64, - pub message_type: MessageType, - pub body: String, - pub metadata: Option, - pub pinned: bool, - pub system: bool, - pub edited_at: Option>, - pub deleted_at: Option>, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/message_attachments.rs b/models/channels/message_attachments.rs deleted file mode 100644 index 20a22c9..0000000 --- a/models/channels/message_attachments.rs +++ /dev/null @@ -1,21 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageAttachment { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub filename: String, - pub url: String, - pub proxy_url: Option, - pub size_bytes: i64, - pub mime_type: String, - pub width: Option, - pub height: Option, - pub duration_ms: Option, - pub thumbnail_url: Option, - pub blurhash: Option, - pub created_at: DateTime, -} diff --git a/models/channels/message_bookmarks.rs b/models/channels/message_bookmarks.rs deleted file mode 100644 index d42d2da..0000000 --- a/models/channels/message_bookmarks.rs +++ /dev/null @@ -1,14 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageBookmark { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub user_id: Uuid, - pub note: Option, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/message_drafts.rs b/models/channels/message_drafts.rs deleted file mode 100644 index 0be57e6..0000000 --- a/models/channels/message_drafts.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::models::common::JsonValue; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageDraft { - pub id: Uuid, - pub user_id: Uuid, - pub channel_id: Uuid, - pub thread_id: Option, - pub reply_to_message_id: Option, - pub content: String, - pub attachments: Option, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/message_edit_history.rs b/models/channels/message_edit_history.rs deleted file mode 100644 index b48308a..0000000 --- a/models/channels/message_edit_history.rs +++ /dev/null @@ -1,13 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageEditHistory { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub previous_body: String, - pub edited_by: Uuid, - pub edited_at: DateTime, -} diff --git a/models/channels/message_embeds.rs b/models/channels/message_embeds.rs deleted file mode 100644 index ed94b2f..0000000 --- a/models/channels/message_embeds.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::models::common::{EmbedType, JsonValue}; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageEmbed { - pub id: Uuid, - pub message_id: Uuid, - pub embed_type: EmbedType, - pub title: Option, - pub description: Option, - pub url: Option, - pub author_name: Option, - pub author_url: Option, - pub author_icon_url: Option, - pub thumbnail_url: Option, - pub thumbnail_width: Option, - pub thumbnail_height: Option, - pub image_url: Option, - pub image_width: Option, - pub image_height: Option, - pub video_url: Option, - pub video_width: Option, - pub video_height: Option, - pub color: Option, - pub fields: Option, - pub footer_text: Option, - pub footer_icon_url: Option, - pub provider_name: Option, - pub provider_url: Option, - pub timestamp: Option>, - pub created_at: DateTime, -} diff --git a/models/channels/message_mentions.rs b/models/channels/message_mentions.rs deleted file mode 100644 index 837a628..0000000 --- a/models/channels/message_mentions.rs +++ /dev/null @@ -1,14 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageMention { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub mentioned_user_id: Uuid, - pub mentioned_by: Uuid, - pub read_at: Option>, - pub created_at: DateTime, -} diff --git a/models/channels/message_pins.rs b/models/channels/message_pins.rs deleted file mode 100644 index 67e2586..0000000 --- a/models/channels/message_pins.rs +++ /dev/null @@ -1,12 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessagePin { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub pinned_by: Uuid, - pub pinned_at: DateTime, -} diff --git a/models/channels/message_poll_options.rs b/models/channels/message_poll_options.rs deleted file mode 100644 index 84d7348..0000000 --- a/models/channels/message_poll_options.rs +++ /dev/null @@ -1,16 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Poll option. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessagePollOption { - pub id: Uuid, - pub poll_id: Uuid, - pub position: i32, - pub text: String, - pub emoji_id: Option, - pub emoji_name: Option, - pub vote_count: i64, - pub created_at: DateTime, -} diff --git a/models/channels/message_poll_votes.rs b/models/channels/message_poll_votes.rs deleted file mode 100644 index 52bedef..0000000 --- a/models/channels/message_poll_votes.rs +++ /dev/null @@ -1,13 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// User vote record for a poll option. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessagePollVote { - pub id: Uuid, - pub poll_id: Uuid, - pub option_id: Uuid, - pub user_id: Uuid, - pub voted_at: DateTime, -} diff --git a/models/channels/message_polls.rs b/models/channels/message_polls.rs deleted file mode 100644 index 13269eb..0000000 --- a/models/channels/message_polls.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::models::common::{JsonValue, PollLayout}; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -/// Message poll (similar to Discord Polls). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessagePoll { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub question: String, - pub description: Option, - pub layout: PollLayout, - pub allow_multiselect: bool, - pub duration_hours: Option, - pub ends_at: Option>, - pub total_votes: i64, - pub metadata: Option, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/message_reactions.rs b/models/channels/message_reactions.rs deleted file mode 100644 index 7241d35..0000000 --- a/models/channels/message_reactions.rs +++ /dev/null @@ -1,13 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageReaction { - pub id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub user_id: Uuid, - pub content: String, - pub created_at: DateTime, -} diff --git a/models/channels/message_threads.rs b/models/channels/message_threads.rs deleted file mode 100644 index a534245..0000000 --- a/models/channels/message_threads.rs +++ /dev/null @@ -1,27 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct MessageThread { - pub id: Uuid, - pub channel_id: Uuid, - pub root_message_id: Uuid, - pub created_by: Uuid, - pub replies_count: i64, - pub participants_count: i64, - pub last_reply_message_id: Option, - pub last_reply_at: Option>, - pub resolved: bool, - pub resolved_by: Option, - pub resolved_at: Option>, - // ── Forum post specific ── - pub title: Option, - pub tags: Vec, - pub pinned: bool, - pub locked: bool, - pub rate_limit_per_user: Option, - pub auto_archive_at: Option>, - pub created_at: DateTime, - pub updated_at: DateTime, -} diff --git a/models/channels/mod.rs b/models/channels/mod.rs index e74dc2a..285bc23 100644 --- a/models/channels/mod.rs +++ b/models/channels/mod.rs @@ -1,11 +1,6 @@ -pub mod article_comments; -pub mod article_cross_posts; -pub mod article_reactions; -pub mod articles; pub mod channel; pub mod channel_categories; pub mod channel_events; -pub mod channel_follows; pub mod channel_invitations; pub mod channel_member_roles; pub mod channel_members; @@ -17,32 +12,12 @@ pub mod channel_webhooks; pub mod custom_emojis; pub mod forum_tags; pub mod im_integrations; -pub mod message; -pub mod message_attachments; -pub mod message_bookmarks; -pub mod message_drafts; -pub mod message_edit_history; -pub mod message_embeds; -pub mod message_mentions; -pub mod message_pins; -pub mod message_poll_options; -pub mod message_poll_votes; -pub mod message_polls; -pub mod message_reactions; -pub mod message_threads; -pub mod saved_messages; pub mod stages; -pub mod thread_read_states; pub mod voice_participants; -pub use article_comments::ArticleComment; -pub use article_cross_posts::ArticleCrossPost; -pub use article_reactions::ArticleReaction; -pub use articles::Article; -pub use channel::Channel; +pub use channel::{Channel, ChannelDetail}; pub use channel_categories::ChannelCategory; pub use channel_events::ChannelEvent; -pub use channel_follows::ChannelFollow; pub use channel_invitations::ChannelInvitation; pub use channel_member_roles::ChannelMemberRole; pub use channel_members::ChannelMember; @@ -54,20 +29,5 @@ pub use channel_webhooks::ChannelWebhook; pub use custom_emojis::CustomEmoji; pub use forum_tags::ForumTag; pub use im_integrations::ImIntegration; -pub use message::Message; -pub use message_attachments::MessageAttachment; -pub use message_bookmarks::MessageBookmark; -pub use message_drafts::MessageDraft; -pub use message_edit_history::MessageEditHistory; -pub use message_embeds::MessageEmbed; -pub use message_mentions::MessageMention; -pub use message_pins::MessagePin; -pub use message_poll_options::MessagePollOption; -pub use message_poll_votes::MessagePollVote; -pub use message_polls::MessagePoll; -pub use message_reactions::MessageReaction; -pub use message_threads::MessageThread; -pub use saved_messages::SavedMessage; pub use stages::Stage; -pub use thread_read_states::ThreadReadState; pub use voice_participants::VoiceParticipant; diff --git a/models/channels/saved_messages.rs b/models/channels/saved_messages.rs deleted file mode 100644 index a8449f8..0000000 --- a/models/channels/saved_messages.rs +++ /dev/null @@ -1,13 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct SavedMessage { - pub id: Uuid, - pub user_id: Uuid, - pub message_id: Uuid, - pub channel_id: Uuid, - pub note: Option, - pub created_at: DateTime, -} diff --git a/models/channels/thread_read_states.rs b/models/channels/thread_read_states.rs deleted file mode 100644 index 6c6ebbe..0000000 --- a/models/channels/thread_read_states.rs +++ /dev/null @@ -1,14 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] -pub struct ThreadReadState { - pub id: Uuid, - pub user_id: Uuid, - pub thread_id: Uuid, - pub channel_id: Uuid, - pub last_read_message_id: Option, - pub last_read_at: Option>, - pub updated_at: DateTime, -} diff --git a/models/issues/issue.rs b/models/issues/issue.rs index 4b9e76d..e5eda4e 100644 --- a/models/issues/issue.rs +++ b/models/issues/issue.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use crate::models::common::{Priority, State, Visibility}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -23,3 +24,48 @@ pub struct Issue { pub updated_at: DateTime, pub deleted_at: Option>, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct IssueDetail { + pub id: Uuid, + pub workspace_id: Uuid, + pub author: UserBaseInfo, + pub number: i64, + pub title: String, + pub body: Option, + pub state: State, + pub priority: Priority, + pub visibility: Visibility, + pub locked: bool, + pub milestone_id: Option, + pub closed_by: Option, + pub closed_at: Option>, + pub due_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl Issue { + pub fn into_detail(self, author: UserBaseInfo) -> IssueDetail { + IssueDetail { + id: self.id, + workspace_id: self.workspace_id, + author, + number: self.number, + title: self.title, + body: self.body, + state: self.state, + priority: self.priority, + visibility: self.visibility, + locked: self.locked, + milestone_id: self.milestone_id, + closed_by: self.closed_by, + closed_at: self.closed_at, + due_at: self.due_at, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +} diff --git a/models/issues/issue_comments.rs b/models/issues/issue_comments.rs index 589281d..f521b28 100644 --- a/models/issues/issue_comments.rs +++ b/models/issues/issue_comments.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -14,3 +15,30 @@ pub struct IssueComment { pub created_at: DateTime, pub updated_at: DateTime, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct IssueCommentDetail { + pub id: Uuid, + pub issue_id: Uuid, + pub author: UserBaseInfo, + pub reply_to_comment_id: Option, + pub body: String, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl IssueComment { + pub fn into_detail(self, author: UserBaseInfo) -> IssueCommentDetail { + IssueCommentDetail { + id: self.id, + issue_id: self.issue_id, + author, + reply_to_comment_id: self.reply_to_comment_id, + body: self.body, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +} diff --git a/models/issues/mod.rs b/models/issues/mod.rs index e799d92..d4e7c19 100644 --- a/models/issues/mod.rs +++ b/models/issues/mod.rs @@ -15,9 +15,9 @@ pub mod issue_stats; pub mod issue_subscribers; pub mod issue_templates; -pub use issue::Issue; +pub use issue::{Issue, IssueDetail}; pub use issue_assignees::IssueAssignee; -pub use issue_comments::IssueComment; +pub use issue_comments::{IssueComment, IssueCommentDetail}; pub use issue_commit_relations::IssueCommitRelation; pub use issue_events::IssueEvent; pub use issue_label_relations::IssueLabelRelation; diff --git a/models/mod.rs b/models/mod.rs index fc236dd..4aab156 100644 --- a/models/mod.rs +++ b/models/mod.rs @@ -1,5 +1,6 @@ pub mod agents; pub mod ais; +pub mod base_info; pub mod channels; pub mod common; pub mod conversations; diff --git a/models/notifications/mod.rs b/models/notifications/mod.rs index bfec37b..81192c9 100644 --- a/models/notifications/mod.rs +++ b/models/notifications/mod.rs @@ -4,7 +4,7 @@ pub mod notification_deliveries; pub mod notification_subscriptions; pub mod notification_templates; -pub use notification::Notification; +pub use notification::{Notification, NotificationDetail}; pub use notification_blocks::NotificationBlock; pub use notification_deliveries::NotificationDelivery; pub use notification_subscriptions::NotificationSubscription; diff --git a/models/notifications/notification.rs b/models/notifications/notification.rs index 7281779..edcb96f 100644 --- a/models/notifications/notification.rs +++ b/models/notifications/notification.rs @@ -1,10 +1,11 @@ +use crate::models::base_info::{RepoBaseInfo, UserBaseInfo, WorkspaceBaseInfo}; use crate::models::common::{NotificationType, Priority, TargetType}; use crate::models::json_types::{NotificationMetadata, TypedJson}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct Notification { pub id: Uuid, pub user_id: Uuid, @@ -24,8 +25,70 @@ pub struct Notification { pub priority: Priority, pub read_at: Option>, pub dismissed_at: Option>, + #[schema(value_type = serde_json::Value)] pub metadata: Option>, pub created_at: DateTime, pub updated_at: DateTime, pub deleted_at: Option>, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct NotificationDetail { + pub id: Uuid, + pub user_id: Uuid, + pub actor: Option, + pub workspace: Option, + pub repo: Option, + pub issue_id: Option, + pub pull_request_id: Option, + pub channel_id: Option, + pub message_id: Option, + pub notification_type: NotificationType, + pub title: String, + pub body: Option, + pub target_type: Option, + pub target_id: Option, + pub action_url: Option, + pub priority: Priority, + pub read_at: Option>, + pub dismissed_at: Option>, + #[schema(value_type = serde_json::Value)] + pub metadata: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl Notification { + pub fn into_detail( + self, + actor: Option, + workspace: Option, + repo: Option, + ) -> NotificationDetail { + NotificationDetail { + id: self.id, + user_id: self.user_id, + actor, + workspace, + repo, + issue_id: self.issue_id, + pull_request_id: self.pull_request_id, + channel_id: self.channel_id, + message_id: self.message_id, + notification_type: self.notification_type, + title: self.title, + body: self.body, + target_type: self.target_type, + target_id: self.target_id, + action_url: self.action_url, + priority: self.priority, + read_at: self.read_at, + dismissed_at: self.dismissed_at, + metadata: self.metadata, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +} diff --git a/models/notifications/notification_blocks.rs b/models/notifications/notification_blocks.rs index 36e7863..271ffd8 100644 --- a/models/notifications/notification_blocks.rs +++ b/models/notifications/notification_blocks.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct NotificationBlock { pub id: Uuid, pub user_id: Uuid, diff --git a/models/notifications/notification_deliveries.rs b/models/notifications/notification_deliveries.rs index a6dbfac..160a1d3 100644 --- a/models/notifications/notification_deliveries.rs +++ b/models/notifications/notification_deliveries.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct NotificationDelivery { pub id: Uuid, pub notification_id: Uuid, diff --git a/models/notifications/notification_subscriptions.rs b/models/notifications/notification_subscriptions.rs index 7d019f4..9d14112 100644 --- a/models/notifications/notification_subscriptions.rs +++ b/models/notifications/notification_subscriptions.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct NotificationSubscription { pub id: Uuid, pub user_id: Uuid, diff --git a/models/notifications/notification_templates.rs b/models/notifications/notification_templates.rs index 98c2471..bcbbc34 100644 --- a/models/notifications/notification_templates.rs +++ b/models/notifications/notification_templates.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct NotificationTemplate { pub id: Uuid, pub key: String, diff --git a/models/prs/mod.rs b/models/prs/mod.rs index 7ab8f16..20d717c 100644 --- a/models/prs/mod.rs +++ b/models/prs/mod.rs @@ -9,8 +9,10 @@ pub mod pr_merge_strategy; pub mod pr_reactions; pub mod pr_review; pub mod pr_review_comment; +pub mod pr_review_requests; pub mod pr_status; pub mod pr_subscriptions; +pub mod pr_templates; pub mod pull_request; pub mod pull_request_queries; @@ -23,8 +25,10 @@ pub use pr_label_relations::PrLabelRelation; pub use pr_labels::PrLabel; pub use pr_merge_strategy::PrMergeStrategy; pub use pr_reactions::PrReaction; -pub use pr_review::PrReview; +pub use pr_review::{PrReview, PrReviewDetail}; pub use pr_review_comment::PrReviewComment; +pub use pr_review_requests::PrReviewRequest; pub use pr_status::PrStatus; pub use pr_subscriptions::PrSubscription; -pub use pull_request::PullRequest; +pub use pr_templates::PrTemplate; +pub use pull_request::{PullRequest, PullRequestDetail}; diff --git a/models/prs/pr_review.rs b/models/prs/pr_review.rs index 8cdd3b3..e023ead 100644 --- a/models/prs/pr_review.rs +++ b/models/prs/pr_review.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -17,3 +18,34 @@ pub struct PrReview { pub created_at: DateTime, pub updated_at: DateTime, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct PrReviewDetail { + pub id: Uuid, + pub pull_request_id: Uuid, + pub author: UserBaseInfo, + pub state: String, + pub body: Option, + pub dismissed: bool, + pub dismissed_by: Option, + pub dismissed_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +impl PrReview { + pub fn into_detail(self, author: UserBaseInfo) -> PrReviewDetail { + PrReviewDetail { + id: self.id, + pull_request_id: self.pull_request_id, + author, + state: self.state, + body: self.body, + dismissed: self.dismissed_at.is_some(), + dismissed_by: self.dismissed_by, + dismissed_at: self.dismissed_at, + created_at: self.created_at, + updated_at: self.updated_at, + } + } +} diff --git a/models/prs/pr_review_requests.rs b/models/prs/pr_review_requests.rs new file mode 100644 index 0000000..3849663 --- /dev/null +++ b/models/prs/pr_review_requests.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] +pub struct PrReviewRequest { + pub id: Uuid, + pub pull_request_id: Uuid, + pub reviewer_id: Uuid, + pub requested_by: Uuid, + pub created_at: chrono::DateTime, +} diff --git a/models/prs/pr_templates.rs b/models/prs/pr_templates.rs new file mode 100644 index 0000000..8002883 --- /dev/null +++ b/models/prs/pr_templates.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] +pub struct PrTemplate { + pub id: Uuid, + pub repo_id: Uuid, + pub name: String, + pub description: Option, + pub title_template: Option, + pub body_template: String, + pub labels: Vec, + pub active: bool, + pub created_by: Option, + pub created_at: chrono::DateTime, + pub updated_at: chrono::DateTime, +} diff --git a/models/prs/pull_request.rs b/models/prs/pull_request.rs index 2ccc524..64bd6be 100644 --- a/models/prs/pull_request.rs +++ b/models/prs/pull_request.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use crate::models::common::State; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -29,3 +30,60 @@ pub struct PullRequest { pub updated_at: DateTime, pub deleted_at: Option>, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct PullRequestDetail { + pub id: Uuid, + pub repo_id: Uuid, + pub author: UserBaseInfo, + pub number: i64, + pub title: String, + pub body: Option, + pub state: State, + pub source_repo_id: Uuid, + pub source_branch: String, + pub target_repo_id: Uuid, + pub target_branch: String, + pub base_commit_sha: Option, + pub head_commit_sha: String, + pub merge_commit_sha: Option, + pub draft: bool, + pub locked: bool, + pub merged_by: Option, + pub merged_at: Option>, + pub closed_by: Option, + pub closed_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl PullRequest { + pub fn into_detail(self, author: UserBaseInfo) -> PullRequestDetail { + PullRequestDetail { + id: self.id, + repo_id: self.repo_id, + author, + number: self.number, + title: self.title, + body: self.body, + state: self.state, + source_repo_id: self.source_repo_id, + source_branch: self.source_branch, + target_repo_id: self.target_repo_id, + target_branch: self.target_branch, + base_commit_sha: self.base_commit_sha, + head_commit_sha: self.head_commit_sha, + merge_commit_sha: self.merge_commit_sha, + draft: self.draft, + locked: self.locked, + merged_by: self.merged_by, + merged_at: self.merged_at, + closed_by: self.closed_by, + closed_at: self.closed_at, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +} diff --git a/models/repos/mod.rs b/models/repos/mod.rs index 64bfa66..d84bdea 100644 --- a/models/repos/mod.rs +++ b/models/repos/mod.rs @@ -10,6 +10,7 @@ pub mod repo_members; pub mod repo_push_commit; pub mod repo_push_lock; pub mod repo_queries; +pub mod repo_release_assets; pub mod repo_releases; pub mod repo_stars; pub mod repo_stats; @@ -18,7 +19,7 @@ pub mod repo_watches; pub mod repo_webhooks; pub use branch_protection_rule::BranchProtectionRule; -pub use repo::Repo; +pub use repo::{Repo, RepoDetail}; pub use repo_branches::RepoBranch; pub use repo_commit_comments::RepoCommitComment; pub use repo_commit_statuses::RepoCommitStatus; @@ -28,6 +29,7 @@ pub use repo_invitations::RepoInvitation; pub use repo_members::RepoMember; pub use repo_push_commit::RepoPushCommit; pub use repo_push_lock::RepoPushLock; +pub use repo_release_assets::RepoReleaseAsset; pub use repo_releases::RepoRelease; pub use repo_stars::RepoStar; pub use repo_stats::RepoStats; diff --git a/models/repos/repo.rs b/models/repos/repo.rs index 7b6c0ad..6d1e7f9 100644 --- a/models/repos/repo.rs +++ b/models/repos/repo.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::{UserBaseInfo, WorkspaceBaseInfo}; use crate::models::common::{GitService, Status, Visibility}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -23,4 +24,91 @@ pub struct Repo { pub created_at: DateTime, pub updated_at: DateTime, pub deleted_at: Option>, + #[sqlx(default)] + pub topics: Vec, + #[sqlx(default)] + pub homepage: Option, + #[sqlx(default)] + pub has_issues: bool, + #[sqlx(default)] + pub has_wiki: bool, + #[sqlx(default)] + pub has_pull_requests: bool, + #[sqlx(default)] + pub allow_forking: bool, + #[sqlx(default)] + pub allow_merge_commit: bool, + #[sqlx(default)] + pub allow_squash_merge: bool, + #[sqlx(default)] + pub allow_rebase_merge: bool, + #[sqlx(default)] + pub delete_branch_on_merge: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct RepoDetail { + pub id: Uuid, + pub workspace: WorkspaceBaseInfo, + pub owner: UserBaseInfo, + pub name: String, + pub description: Option, + pub default_branch: String, + pub visibility: Visibility, + pub status: Status, + pub is_fork: bool, + pub forked_from_repo_id: Option, + pub storage_node_ids: Vec, + pub primary_storage_node_id: Uuid, + pub storage_path: String, + pub git_service: GitService, + pub archived_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, + pub topics: Vec, + pub homepage: Option, + pub has_issues: bool, + pub has_wiki: bool, + pub has_pull_requests: bool, + pub allow_forking: bool, + pub allow_merge_commit: bool, + pub allow_squash_merge: bool, + pub allow_rebase_merge: bool, + pub delete_branch_on_merge: bool, +} + +impl Repo { + pub fn into_detail(self, owner: UserBaseInfo, workspace: WorkspaceBaseInfo) -> RepoDetail { + RepoDetail { + id: self.id, + workspace, + owner, + name: self.name, + description: self.description, + default_branch: self.default_branch, + visibility: self.visibility, + status: self.status, + is_fork: self.is_fork, + forked_from_repo_id: self.forked_from_repo_id, + storage_node_ids: self.storage_node_ids, + primary_storage_node_id: self.primary_storage_node_id, + storage_path: self.storage_path, + git_service: self.git_service, + archived_at: self.archived_at, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + topics: self.topics, + homepage: self.homepage, + has_issues: self.has_issues, + has_wiki: self.has_wiki, + has_pull_requests: self.has_pull_requests, + allow_forking: self.allow_forking, + allow_merge_commit: self.allow_merge_commit, + allow_squash_merge: self.allow_squash_merge, + allow_rebase_merge: self.allow_rebase_merge, + delete_branch_on_merge: self.delete_branch_on_merge, + } + } } diff --git a/models/repos/repo_release_assets.rs b/models/repos/repo_release_assets.rs new file mode 100644 index 0000000..3df49f1 --- /dev/null +++ b/models/repos/repo_release_assets.rs @@ -0,0 +1,19 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] +pub struct RepoReleaseAsset { + pub id: Uuid, + pub release_id: Uuid, + pub filename: String, + pub size_bytes: i64, + pub mime_type: String, + pub storage_path: String, + pub url: Option, + pub download_count: i64, + pub uploaded_by: Option, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} diff --git a/models/users/user.rs b/models/users/user.rs index 9b6be71..18be483 100644 --- a/models/users/user.rs +++ b/models/users/user.rs @@ -19,4 +19,8 @@ pub struct User { pub created_at: DateTime, pub updated_at: DateTime, pub deleted_at: Option>, + #[sqlx(default)] + pub restore_token_hash: Option, + #[sqlx(default)] + pub restore_token_expires_at: Option>, } diff --git a/models/users/user_block.rs b/models/users/user_block.rs index 5bf5b36..f97927b 100644 --- a/models/users/user_block.rs +++ b/models/users/user_block.rs @@ -2,7 +2,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct UserBlock { pub blocker_id: Uuid, pub blocked_id: Uuid, diff --git a/models/users/user_follow.rs b/models/users/user_follow.rs index 07e7ac4..6b69600 100644 --- a/models/users/user_follow.rs +++ b/models/users/user_follow.rs @@ -2,7 +2,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct UserFollow { pub follower_id: Uuid, pub following_id: Uuid, diff --git a/models/users/user_presence.rs b/models/users/user_presence.rs index 0130ed8..6262813 100644 --- a/models/users/user_presence.rs +++ b/models/users/user_presence.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow, utoipa::ToSchema)] pub struct UserPresence { pub id: Uuid, pub user_id: Uuid, diff --git a/models/workspaces/mod.rs b/models/workspaces/mod.rs index c07a519..0b0526a 100644 --- a/models/workspaces/mod.rs +++ b/models/workspaces/mod.rs @@ -12,7 +12,7 @@ pub mod workspace_settings; pub mod workspace_stats; pub mod workspace_webhooks; -pub use workspace::Workspace; +pub use workspace::{Workspace, WorkspaceDetail}; pub use workspace_audit_logs::WorkspaceAuditLog; pub use workspace_billing::WorkspaceBilling; pub use workspace_custom_branding::WorkspaceCustomBranding; diff --git a/models/workspaces/workspace.rs b/models/workspaces/workspace.rs index 5cd2c9b..3a1295a 100644 --- a/models/workspaces/workspace.rs +++ b/models/workspaces/workspace.rs @@ -1,3 +1,4 @@ +use crate::models::base_info::UserBaseInfo; use crate::models::common::{Status, Visibility}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -20,3 +21,42 @@ pub struct Workspace { pub updated_at: DateTime, pub deleted_at: Option>, } + +#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] +pub struct WorkspaceDetail { + pub id: Uuid, + pub owner: UserBaseInfo, + pub name: String, + pub description: Option, + pub avatar_url: Option, + pub visibility: Visibility, + pub plan: String, + pub status: Status, + pub default_role: String, + pub is_personal: bool, + pub archived_at: Option>, + pub created_at: DateTime, + pub updated_at: DateTime, + pub deleted_at: Option>, +} + +impl Workspace { + pub fn into_detail(self, owner: UserBaseInfo) -> WorkspaceDetail { + WorkspaceDetail { + id: self.id, + owner, + name: self.name, + description: self.description, + avatar_url: self.avatar_url, + visibility: self.visibility, + plan: self.plan, + status: self.status, + default_role: self.default_role, + is_personal: self.is_personal, + archived_at: self.archived_at, + created_at: self.created_at, + updated_at: self.updated_at, + deleted_at: self.deleted_at, + } + } +}