d5939db
use db::conn::sea_orm::*;
use db::git::git_commit_status as status_entity;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::error::{RepoError, RepoResult};
use crate::features::RepoService;
use super::types::{
CombinedStatusView, CommitStatusPage, CommitStatusView, CreateStatusOption, ListStatusQuery,
parse_state_pub,
};
fn require_authenticated(actor: Uuid) -> RepoResult<()> {
if actor.is_nil() {
return Err(RepoError::Unauthorized("authentication required".into()));
}
Ok(())
}
fn aggregate_state(items: &[status_entity::Model]) -> &'static str {
let mut has_failure = false;
let mut has_error = false;
let mut has_pending = false;
let mut has_success = false;
for m in items {
match m.state {
status_entity::CommitStatusState::Failure => has_failure = true,
status_entity::CommitStatusState::Error => has_error = true,
status_entity::CommitStatusState::Pending => has_pending = true,
status_entity::CommitStatusState::Success => has_success = true,
}
}
if has_failure || has_error {
"failure"
} else if has_pending {
"pending"
} else if has_success {
"success"
} else {
"pending"
}
}
pub async fn list_commit_statuses(
svc: &RepoService,
actor: Uuid,
repo_id: Uuid,
sha: &str,
q: ListStatusQuery,
) -> RepoResult<CommitStatusPage> {
let _ = actor;
let limit = q.limit.unwrap_or(svc.config.default_pagination);
let offset = q.page.unwrap_or(0).saturating_mul(limit);
let limit = std::cmp::min(limit, svc.config.max_pagination);
let db = svc.db.reader();
let mut query = status_entity::Entity::find()
.filter(status_entity::Column::RepoId.eq(repo_id))
.filter(status_entity::Column::Sha.eq(sha));
if let Some(s) = q.state.as_deref() {
let parsed = parse_state_pub(s)?;
query = query.filter(status_entity::Column::State.eq(parsed));
}
let total = query.clone().count(&db).await?;
let items = query
.order_by_desc(status_entity::Column::CreatedAt)
.limit(Some(limit))
.offset(Some(offset))
.all(&db)
.await?
.into_iter()
.map(CommitStatusView::from)
.collect();
Ok(CommitStatusPage {
items,
total: total as i64,
})
}
pub async fn create_commit_status(
svc: &RepoService,
actor: Uuid,
repo_id: Uuid,
sha: &str,
input: CreateStatusOption,
) -> RepoResult<CommitStatusView> {
require_authenticated(actor)?;
let state = parse_state_pub(&input.state)?;
let db = svc.db.writer();
let now = OffsetDateTime::now_utc();
let active: status_entity::ActiveModel = status_entity::ActiveModel {
id: Set(Uuid::new_v4()),
repo_id: Set(repo_id),
sha: Set(sha.to_string()),
state: Set(state),
context: Set(input.context),
description: Set(input.description),
target_url: Set(input.target_url),
creator_id: Set(actor),
created_at: Set(now),
updated_at: Set(Some(now)),
};
let saved = active.insert(&db).await?;
Ok(CommitStatusView::from(saved))
}
pub async fn list_commit_statuses_by_ref(
svc: &RepoService,
actor: Uuid,
repo_id: Uuid,
git_ref: &str,
q: ListStatusQuery,
) -> RepoResult<CommitStatusPage> {
let _ = actor;
let sha = resolve_ref(svc, repo_id, git_ref).await?;
list_commit_statuses(svc, actor, repo_id, &sha, q).await
}
pub async fn combined_status_by_ref(
svc: &RepoService,
actor: Uuid,
repo_id: Uuid,
git_ref: &str,
) -> RepoResult<CombinedStatusView> {
let _ = actor;
let sha = resolve_ref(svc, repo_id, git_ref).await?;
let db = svc.db.reader();
let items = status_entity::Entity::find()
.filter(status_entity::Column::RepoId.eq(repo_id))
.filter(status_entity::Column::Sha.eq(&sha))
.all(&db)
.await?;
let total = items.len() as i64;
let state = aggregate_state(&items).to_string();
let statuses: Vec<CommitStatusView> = items.into_iter().map(CommitStatusView::from).collect();
Ok(CombinedStatusView {
sha,
state,
statuses,
total_count: total,
})
}
async fn resolve_ref(_svc: &RepoService, _repo_id: Uuid, git_ref: &str) -> RepoResult<String> {
if git_ref.is_empty() {
return Err(RepoError::BadRequest("ref is empty".into()));
}
Ok(git_ref.to_string())
}