245 lines
6.7 KiB
Rust
245 lines
6.7 KiB
Rust
//! Skill management API endpoints.
|
|
|
|
use actix_web::{HttpResponse, Result, web};
|
|
use service::AppService;
|
|
use session::Session;
|
|
|
|
use crate::{ApiResponse, error::ApiError};
|
|
|
|
#[derive(serde::Deserialize, utoipa::IntoParams)]
|
|
pub struct SkillPath {
|
|
pub project_name: String,
|
|
pub slug: String,
|
|
}
|
|
|
|
#[derive(Debug, serde::Deserialize, utoipa::IntoParams)]
|
|
pub struct SkillQuery {
|
|
pub source: Option<String>,
|
|
pub enabled: Option<bool>,
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/api/projects/{project_name}/skills",
|
|
params(
|
|
("project_name" = String, Path),
|
|
),
|
|
responses(
|
|
(status = 200, description = "List skills", body = ApiResponse<Vec<service::skill::info::SkillResponse>>),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 404, description = "Project not found"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_list(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<String>,
|
|
query: web::Query<SkillQuery>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let project_name = path.into_inner();
|
|
let project = service
|
|
.project_info(&session, project_name.clone())
|
|
.await?;
|
|
|
|
let q = service::skill::info::SkillListQuery {
|
|
source: query.source.clone(),
|
|
enabled: query.enabled,
|
|
};
|
|
|
|
let skills = service
|
|
.skill_list(project.uid.to_string(), q, &session)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(skills).to_response())
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/api/projects/{project_name}/skills/{slug}",
|
|
params(
|
|
("project_name" = String, Path),
|
|
("slug" = String, Path),
|
|
),
|
|
responses(
|
|
(status = 200, description = "Get skill", body = ApiResponse<service::skill::info::SkillResponse>),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 404, description = "Not found"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_get(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<SkillPath>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let SkillPath {
|
|
project_name,
|
|
slug,
|
|
} = path.into_inner();
|
|
|
|
let project = service
|
|
.project_info(&session, project_name.clone())
|
|
.await?;
|
|
|
|
let skill = service
|
|
.skill_get(project.uid.to_string(), slug, &session)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(skill).to_response())
|
|
}
|
|
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/api/projects/{project_name}/skills",
|
|
params(("project_name" = String, Path)),
|
|
request_body = service::skill::manage::CreateSkillRequest,
|
|
responses(
|
|
(status = 200, description = "Create skill", body = ApiResponse<service::skill::info::SkillResponse>),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 409, description = "Skill already exists"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_create(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<String>,
|
|
body: web::Json<service::skill::manage::CreateSkillRequest>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let project_name = path.into_inner();
|
|
let project = service
|
|
.project_info(&session, project_name.clone())
|
|
.await?;
|
|
|
|
let skill = service
|
|
.skill_create(project.uid.to_string(), body.into_inner(), &session)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(skill).to_response())
|
|
}
|
|
|
|
#[utoipa::path(
|
|
patch,
|
|
path = "/api/projects/{project_name}/skills/{slug}",
|
|
params(
|
|
("project_name" = String, Path),
|
|
("slug" = String, Path),
|
|
),
|
|
request_body = service::skill::manage::UpdateSkillRequest,
|
|
responses(
|
|
(status = 200, description = "Update skill", body = ApiResponse<service::skill::info::SkillResponse>),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 404, description = "Not found"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_update(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<SkillPath>,
|
|
body: web::Json<service::skill::manage::UpdateSkillRequest>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let SkillPath {
|
|
project_name,
|
|
slug,
|
|
} = path.into_inner();
|
|
|
|
let project = service
|
|
.project_info(&session, project_name.clone())
|
|
.await?;
|
|
|
|
let skill = service
|
|
.skill_update(project.uid.to_string(), slug, body.into_inner(), &session)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(skill).to_response())
|
|
}
|
|
|
|
#[utoipa::path(
|
|
delete,
|
|
path = "/api/projects/{project_name}/skills/{slug}",
|
|
params(
|
|
("project_name" = String, Path),
|
|
("slug" = String, Path),
|
|
),
|
|
responses(
|
|
(status = 200, description = "Delete skill", body = ApiResponse<service::skill::manage::DeleteSkillResponse>),
|
|
(status = 401, description = "Unauthorized"),
|
|
(status = 404, description = "Not found"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_delete(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<SkillPath>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let SkillPath {
|
|
project_name,
|
|
slug,
|
|
} = path.into_inner();
|
|
|
|
let project = service
|
|
.project_info(&session, project_name.clone())
|
|
.await?;
|
|
|
|
let result = service
|
|
.skill_delete(project.uid.to_string(), slug, &session)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(result).to_response())
|
|
}
|
|
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/api/projects/{project_name}/skills/scan",
|
|
params(("project_name" = String, Path)),
|
|
responses(
|
|
(status = 200, description = "Scan repos for skills", body = ApiResponse<ScanResponse>),
|
|
(status = 401, description = "Unauthorized"),
|
|
),
|
|
tag = "Skill"
|
|
)]
|
|
pub async fn skill_scan(
|
|
service: web::Data<AppService>,
|
|
session: Session,
|
|
path: web::Path<String>,
|
|
) -> Result<HttpResponse, ApiError> {
|
|
let project_name = path.into_inner();
|
|
let project = service
|
|
.project_info(&session, project_name)
|
|
.await?;
|
|
|
|
let result = service
|
|
.skill_scan_repos(project.uid, project.uid)
|
|
.await?;
|
|
|
|
Ok(ApiResponse::ok(ScanResponse {
|
|
discovered: result.discovered,
|
|
created: result.created,
|
|
updated: result.updated,
|
|
removed: result.removed,
|
|
}).to_response())
|
|
}
|
|
|
|
#[derive(serde::Serialize, utoipa::ToSchema)]
|
|
pub struct ScanResponse {
|
|
pub discovered: i64,
|
|
pub created: i64,
|
|
pub updated: i64,
|
|
pub removed: i64,
|
|
}
|
|
|
|
pub fn init_skill_routes(cfg: &mut web::ServiceConfig) {
|
|
cfg.service(
|
|
web::scope("/projects/{project_name}/skills")
|
|
.route("", web::get().to(skill_list))
|
|
.route("", web::post().to(skill_create))
|
|
.route("/scan", web::post().to(skill_scan))
|
|
.route("/{slug}", web::get().to(skill_get))
|
|
.route("/{slug}", web::patch().to(skill_update))
|
|
.route("/{slug}", web::delete().to(skill_delete)),
|
|
);
|
|
}
|