feat: init
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct BranchProtectionRule {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub pattern: String,
|
||||
pub require_approvals: i32,
|
||||
pub require_status_checks: bool,
|
||||
pub required_status_checks: Vec<String>,
|
||||
pub require_linear_history: bool,
|
||||
pub allow_force_pushes: bool,
|
||||
pub allow_deletions: bool,
|
||||
pub require_signed_commits: bool,
|
||||
pub require_code_owner_review: bool,
|
||||
pub dismiss_stale_reviews: bool,
|
||||
pub restrict_pushes: bool,
|
||||
pub push_allowances: Vec<Uuid>,
|
||||
pub restrict_review_dismissal: bool,
|
||||
pub dismissal_allowances: Vec<Uuid>,
|
||||
pub require_conversation_resolution: bool,
|
||||
pub created_by: Option<Uuid>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
pub mod branch_protection_rule;
|
||||
pub mod repo;
|
||||
pub mod repo_branches;
|
||||
pub mod repo_commit_comments;
|
||||
pub mod repo_commit_statuses;
|
||||
pub mod repo_deploy_keys;
|
||||
pub mod repo_fork;
|
||||
pub mod repo_invitations;
|
||||
pub mod repo_members;
|
||||
pub mod repo_push_commit;
|
||||
pub mod repo_push_lock;
|
||||
pub mod repo_queries;
|
||||
pub mod repo_releases;
|
||||
pub mod repo_stars;
|
||||
pub mod repo_stats;
|
||||
pub mod repo_tags;
|
||||
pub mod repo_watches;
|
||||
pub mod repo_webhooks;
|
||||
|
||||
pub use branch_protection_rule::BranchProtectionRule;
|
||||
pub use repo::Repo;
|
||||
pub use repo_branches::RepoBranch;
|
||||
pub use repo_commit_comments::RepoCommitComment;
|
||||
pub use repo_commit_statuses::RepoCommitStatus;
|
||||
pub use repo_deploy_keys::RepoDeployKey;
|
||||
pub use repo_fork::RepoFork;
|
||||
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_releases::RepoRelease;
|
||||
pub use repo_stars::RepoStar;
|
||||
pub use repo_stats::RepoStats;
|
||||
pub use repo_tags::RepoTag;
|
||||
pub use repo_watches::RepoWatch;
|
||||
pub use repo_webhooks::RepoWebhook;
|
||||
@@ -0,0 +1,26 @@
|
||||
use crate::models::common::{GitService, Status, Visibility};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct Repo {
|
||||
pub id: Uuid,
|
||||
pub workspace_id: Uuid,
|
||||
pub owner_id: Uuid,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub default_branch: String,
|
||||
pub visibility: Visibility,
|
||||
pub status: Status,
|
||||
pub is_fork: bool,
|
||||
pub forked_from_repo_id: Option<Uuid>,
|
||||
pub storage_node_ids: Vec<Uuid>,
|
||||
pub primary_storage_node_id: Uuid,
|
||||
pub storage_path: String,
|
||||
pub git_service: GitService,
|
||||
pub archived_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoBranch {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub name: String,
|
||||
pub commit_sha: String,
|
||||
pub protected: bool,
|
||||
pub default_branch: bool,
|
||||
pub created_by: Option<Uuid>,
|
||||
pub last_push_id: Option<Uuid>,
|
||||
pub last_push_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoCommitComment {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub push_commit_id: Uuid,
|
||||
pub commit_sha: String,
|
||||
pub author_id: Uuid,
|
||||
pub body: String,
|
||||
pub path: Option<String>,
|
||||
pub line: Option<i32>,
|
||||
pub resolved: bool,
|
||||
pub resolved_by: Option<Uuid>,
|
||||
pub resolved_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
use crate::models::common::State;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoCommitStatus {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub push_commit_id: Uuid,
|
||||
pub latest_commit_sha: String,
|
||||
pub context: String,
|
||||
pub state: State,
|
||||
pub target_url: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub reported_by: Option<Uuid>,
|
||||
pub reported_at: DateTime<Utc>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use crate::models::common::KeyType;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoDeployKey {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub title: String,
|
||||
pub public_key: String,
|
||||
pub fingerprint_sha256: String,
|
||||
pub key_type: KeyType,
|
||||
pub read_only: bool,
|
||||
pub last_used_at: Option<DateTime<Utc>>,
|
||||
pub expires_at: Option<DateTime<Utc>>,
|
||||
pub revoked_at: Option<DateTime<Utc>>,
|
||||
pub created_by: Uuid,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoFork {
|
||||
pub id: Uuid,
|
||||
pub parent_repo_id: Uuid,
|
||||
pub fork_repo_id: Uuid,
|
||||
pub forked_by: Uuid,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use crate::models::common::Role;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoInvitation {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub email: String,
|
||||
pub role: Role,
|
||||
pub token_hash: String,
|
||||
pub invited_by: Uuid,
|
||||
pub accepted_by: Option<Uuid>,
|
||||
pub accepted_at: Option<DateTime<Utc>>,
|
||||
pub revoked_at: Option<DateTime<Utc>>,
|
||||
pub expires_at: DateTime<Utc>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use crate::models::common::{Role, Status};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoMember {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub role: Role,
|
||||
pub status: Status,
|
||||
pub invited_by: Option<Uuid>,
|
||||
pub joined_at: Option<DateTime<Utc>>,
|
||||
pub last_active_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoPushCommit {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub pusher_id: Uuid,
|
||||
pub branch_name: String,
|
||||
pub old_commit_sha: Option<String>,
|
||||
pub latest_commit_sha: String,
|
||||
pub commit_shas: Vec<String>,
|
||||
pub commit_count: i32,
|
||||
pub push_status: String,
|
||||
pub pushed_at: DateTime<Utc>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use crate::models::common::Status;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoPushLock {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub pusher_id: Uuid,
|
||||
pub ref_name: String,
|
||||
pub status: Status,
|
||||
pub queue_position: i32,
|
||||
pub queued_at: DateTime<Utc>,
|
||||
pub started_at: Option<DateTime<Utc>>,
|
||||
pub finished_at: Option<DateTime<Utc>>,
|
||||
pub storage_node_id: Option<Uuid>,
|
||||
pub lease_token: Option<String>,
|
||||
pub error_message: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
//! SQL query methods for the `Repo` entity.
|
||||
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::repo::Repo;
|
||||
use crate::models::common::{Role, Visibility};
|
||||
|
||||
impl Repo {
|
||||
/// Find a non-deleted repo by primary key.
|
||||
pub async fn find_by_name(
|
||||
pool: &PgPool,
|
||||
workspace_id: Uuid,
|
||||
name: &str,
|
||||
) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Repo>(
|
||||
"SELECT id, workspace_id, owner_id, name, description, default_branch, visibility, \
|
||||
status, is_fork, forked_from_repo_id, storage_node_ids, \
|
||||
primary_storage_node_id, storage_path, git_service, \
|
||||
archived_at, created_at, updated_at, deleted_at \
|
||||
FROM repo WHERE workspace_id = $1 AND name = $2 AND deleted_at IS NULL",
|
||||
)
|
||||
.bind(workspace_id)
|
||||
.bind(name)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn find_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Repo>(
|
||||
r#"SELECT id, workspace_id, owner_id, name, description, default_branch, visibility,
|
||||
status, is_fork, forked_from_repo_id, storage_node_ids,
|
||||
primary_storage_node_id, storage_path, git_service,
|
||||
archived_at, created_at, updated_at, deleted_at
|
||||
FROM repo WHERE id = $1 AND deleted_at IS NULL"#,
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Check if a user is an active member of a repo.
|
||||
pub async fn is_member(
|
||||
pool: &PgPool,
|
||||
repo_id: Uuid,
|
||||
user_id: Uuid,
|
||||
) -> Result<bool, sqlx::Error> {
|
||||
sqlx::query_scalar::<_, bool>(
|
||||
r#"SELECT EXISTS(
|
||||
SELECT 1 FROM repo_member
|
||||
WHERE repo_id = $1 AND user_id = $2 AND status = 'active'
|
||||
)"#,
|
||||
)
|
||||
.bind(repo_id)
|
||||
.bind(user_id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get the role of a user in a repo.
|
||||
/// Returns `Role::Owner` if the user is the repo owner but has no explicit member row.
|
||||
pub async fn user_role(
|
||||
pool: &PgPool,
|
||||
repo_id: Uuid,
|
||||
user_id: Uuid,
|
||||
owner_id: Uuid,
|
||||
) -> Result<Option<Role>, sqlx::Error> {
|
||||
if owner_id == user_id {
|
||||
return Ok(Some(Role::Owner));
|
||||
}
|
||||
let role_str: Option<String> = sqlx::query_scalar(
|
||||
r#"SELECT role FROM repo_member
|
||||
WHERE repo_id = $1 AND user_id = $2 AND status = 'active'"#,
|
||||
)
|
||||
.bind(repo_id)
|
||||
.bind(user_id)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
Ok(role_str.and_then(|r| r.parse::<Role>().ok()))
|
||||
}
|
||||
|
||||
/// Check if the user can read the repo.
|
||||
/// Readable based on visibility + workspace membership + repo membership.
|
||||
pub async fn is_readable(
|
||||
pool: &PgPool,
|
||||
repo: &Repo,
|
||||
user_id: Uuid,
|
||||
) -> Result<bool, sqlx::Error> {
|
||||
use crate::models::workspaces::Workspace;
|
||||
|
||||
if repo.owner_id == user_id {
|
||||
return Ok(true);
|
||||
}
|
||||
let is_ws_member = Workspace::is_member(pool, repo.workspace_id, user_id).await?;
|
||||
let is_repo_member = Self::is_member(pool, repo.id, user_id).await?;
|
||||
|
||||
Ok(match repo.visibility {
|
||||
Visibility::Public => true,
|
||||
Visibility::Internal => is_ws_member,
|
||||
Visibility::Private => is_ws_member && is_repo_member,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoRelease {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub tag_id: Option<Uuid>,
|
||||
pub tag_name: String,
|
||||
pub title: String,
|
||||
pub body: Option<String>,
|
||||
pub draft: bool,
|
||||
pub prerelease: bool,
|
||||
pub author_id: Uuid,
|
||||
pub published_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoStar {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoStats {
|
||||
pub repo_id: Uuid,
|
||||
pub stars_count: i64,
|
||||
pub watchers_count: i64,
|
||||
pub forks_count: i64,
|
||||
pub branches_count: i64,
|
||||
pub tags_count: i64,
|
||||
pub commits_count: i64,
|
||||
pub releases_count: i64,
|
||||
pub open_issues_count: i64,
|
||||
pub open_pull_requests_count: i64,
|
||||
pub size_bytes: i64,
|
||||
pub last_push_at: Option<DateTime<Utc>>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoTag {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub name: String,
|
||||
pub target_commit_sha: String,
|
||||
pub tagger_id: Option<Uuid>,
|
||||
pub message: Option<String>,
|
||||
pub signed: bool,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use crate::models::common::SubscriptionLevel;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoWatch {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub level: SubscriptionLevel,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use crate::models::common::EventType;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct RepoWebhook {
|
||||
pub id: Uuid,
|
||||
pub repo_id: Uuid,
|
||||
pub url: String,
|
||||
pub secret_ciphertext: Option<String>,
|
||||
pub events: Vec<EventType>,
|
||||
pub active: bool,
|
||||
pub last_delivery_status: Option<String>,
|
||||
pub last_delivery_at: Option<DateTime<Utc>>,
|
||||
pub created_by: Uuid,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
Reference in New Issue
Block a user