//! List and retrieve project skills. use crate::AppService; use crate::error::AppError; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder}; use serde::{Deserialize, Serialize}; use session::Session; use utoipa::ToSchema; #[derive(Debug, Clone, Serialize, ToSchema)] pub struct SkillResponse { pub id: i64, pub project_uuid: String, pub slug: String, pub name: String, pub description: Option, pub source: String, pub repo_id: Option, pub commit_sha: Option, pub blob_hash: Option, pub content: String, pub metadata: serde_json::Value, pub enabled: bool, pub created_by: Option, pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, } impl From for SkillResponse { fn from(s: models::projects::project_skill::Model) -> Self { Self { id: s.id, project_uuid: s.project_uuid.to_string(), slug: s.slug, name: s.name, description: s.description, source: s.source, repo_id: s.repo_id.map(|id| id.to_string()), commit_sha: s.commit_sha, blob_hash: s.blob_hash, content: s.content, metadata: s.metadata, enabled: s.enabled, created_by: s.created_by.map(|id| id.to_string()), created_at: s.created_at, updated_at: s.updated_at, } } } #[derive(Debug, Clone, Deserialize, utoipa::IntoParams)] pub struct SkillListQuery { pub source: Option, pub enabled: Option, } impl AppService { /// List all skills registered to a project. pub async fn skill_list( &self, project_uuid: String, query: SkillListQuery, _ctx: &Session, ) -> Result, AppError> { let project_id = uuid::Uuid::parse_str(&project_uuid) .map_err(|_| AppError::BadRequest("Invalid project UUID".to_string()))?; use models::projects::project_skill::Column as C; let mut q = models::projects::project_skill::Entity::find() .filter(C::ProjectUuid.eq(project_id)) .order_by_asc(C::Name); if let Some(source) = &query.source { q = q.filter(C::Source.eq(source.clone())); } if let Some(enabled) = query.enabled { q = q.filter(C::Enabled.eq(enabled)); } let skills = q.all(&self.db).await?; Ok(skills.into_iter().map(SkillResponse::from).collect()) } /// Get a single skill by slug within a project. pub async fn skill_get( &self, project_uuid: String, slug: String, _ctx: &Session, ) -> Result { let project_id = uuid::Uuid::parse_str(&project_uuid) .map_err(|_| AppError::BadRequest("Invalid project UUID".to_string()))?; use models::projects::project_skill::Column as C; let skill = models::projects::project_skill::Entity::find() .filter(C::ProjectUuid.eq(project_id)) .filter(C::Slug.eq(slug)) .one(&self.db) .await? .ok_or_else(|| AppError::NotFound("Skill not found".to_string()))?; Ok(SkillResponse::from(skill)) } }