refactor(api): reorder imports and update code formatting across repository endpoints
- Reordered actix-web imports to standardize import order - Reordered crate module imports to follow alphabetical ordering - Updated function calls to use multi-line formatting for better readability - Standardized blank lines around documentation comments - Applied consistent formatting to response handling methods - Normalized import organization across all repository-related API files - Improved code consistency and maintainability through standardized formatting - Applied formatting updates to all repository endpoint implementations
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
3.0
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"baseUrl": "https://token-plan-cn.xiaomimimo.com/v1/chat/completions",
|
||||||
|
"id": "mimo-v2.5-pro",
|
||||||
|
"apiKey": "tp-c1ngp1xj5nd7smshsf0t82rex47moenx8mlwobslw7sk0gpv",
|
||||||
|
"apiType": "OpenAICompletion",
|
||||||
|
"primaryModel": {
|
||||||
|
"id": "mimo-v2.5-pro"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueAssignee;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// User ID (UUID) to assign
|
||||||
|
pub user_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assign a user to an issue
|
||||||
|
///
|
||||||
|
/// Assigns a workspace member to the given issue.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - User is assigned to the issue
|
||||||
|
/// - Assignee is automatically subscribed to the issue
|
||||||
|
/// - Issue assignee count is incremented
|
||||||
|
///
|
||||||
|
/// Returns the created assignment record.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/assignees/{user_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueAssign",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "User assigned successfully. Returns the created assignment record.", body = ApiResponse<IssueAssignee>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue or user not found", body = ApiErrorResponse),
|
||||||
|
(status = 409, description = "User is already assigned to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn assign_issue(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let assignee = service
|
||||||
|
.issue
|
||||||
|
.issue_assign(&session, &path.workspace_name, path.number, path.user_id)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(assignee)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueLabelRelation;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// Label ID (UUID) to assign
|
||||||
|
pub label_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assign a label to an issue
|
||||||
|
///
|
||||||
|
/// Attaches a label to the given issue. The label must belong to a repository in the same workspace.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Label is attached to the issue
|
||||||
|
/// - Issue label count is incremented
|
||||||
|
///
|
||||||
|
/// Returns the created label relation.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/labels/{label_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueAssignLabel",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Label assigned successfully. Returns the created label relation.", body = ApiResponse<IssueLabelRelation>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue or label not found", body = ApiErrorResponse),
|
||||||
|
(status = 409, description = "Label is already assigned to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn assign_label(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let rel = service
|
||||||
|
.issue
|
||||||
|
.issue_assign_label(&session, &path.workspace_name, path.number, path.label_id)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(rel)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Close an issue
|
||||||
|
///
|
||||||
|
/// Closes an open issue. The issue is marked as closed and the closing user is recorded.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Issue state changes to "closed"
|
||||||
|
/// - Closed by and closed at are recorded
|
||||||
|
/// - A "Closed" event is logged
|
||||||
|
///
|
||||||
|
/// Returns the closed issue with updated metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/close",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueClose",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue closed successfully. Returns the closed issue with updated metadata.", body = ApiResponse<Issue>),
|
||||||
|
(status = 400, description = "Issue is already closed", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to close this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn close(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_close(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::core::CreateIssueParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an issue
|
||||||
|
///
|
||||||
|
/// Creates a new issue in the specified workspace.
|
||||||
|
/// Requires at least Member role in the workspace.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - title: Issue title (required)
|
||||||
|
/// - body: Issue body in markdown (optional)
|
||||||
|
/// - priority: Priority level (optional, defaults to "none")
|
||||||
|
/// - visibility: Visibility setting (optional, defaults to "public")
|
||||||
|
/// - due_at: Due date (optional)
|
||||||
|
/// - repo_ids: Related repository IDs
|
||||||
|
/// - label_ids: Label IDs to apply
|
||||||
|
/// - assignee_ids: User IDs to assign
|
||||||
|
/// - milestone_id: Milestone ID to attach
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Issue is created with auto-incrementing number
|
||||||
|
/// - Author is automatically subscribed
|
||||||
|
/// - Relations, labels, and assignees are attached
|
||||||
|
/// - Workspace stats are updated
|
||||||
|
///
|
||||||
|
/// Returns the created issue with full metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueCreate",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = CreateIssueParams,
|
||||||
|
description = "Issue creation parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Issue created successfully. Returns the newly created issue with full metadata.", body = ApiResponse<Issue>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty title, invalid repository/label/milestone references", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Member role or higher)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or referenced resource not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn create(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateIssueParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_create(&session, &path.workspace_name, params.into_inner())
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueComment;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::comments::CreateCommentParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a comment on an issue
|
||||||
|
///
|
||||||
|
/// Adds a new comment to an issue. Users with read access can comment unless the issue is locked
|
||||||
|
/// (in which case only users with write access can comment).
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - body: Comment body in markdown format (required)
|
||||||
|
/// - reply_to_comment_id: ID of parent comment for threaded replies (optional)
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Comment is created and attached to the issue
|
||||||
|
/// - Commenter is automatically subscribed to the issue
|
||||||
|
/// - Issue comment count is incremented
|
||||||
|
///
|
||||||
|
/// Returns the created comment with metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/comments",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueCreateComment",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(content = CreateCommentParams, description = "Comment creation parameters", content_type = "application/json"),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Comment created successfully.", body = ApiResponse<IssueComment>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty body or issue is locked", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (issue locked and user lacks write access)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn create_comment(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateCommentParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let comment = service
|
||||||
|
.issue
|
||||||
|
.issue_create_comment(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(comment)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueLabel;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::labels::CreateLabelParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub repo_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a label
|
||||||
|
///
|
||||||
|
/// Creates a new issue label in a repository.
|
||||||
|
/// Requires at least Member role in the repository.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - name: Label name (required, e.g., "bug", "feature")
|
||||||
|
/// - color: Hex color code (required, e.g., "#FF0000")
|
||||||
|
/// - description: Label description (optional)
|
||||||
|
///
|
||||||
|
/// Returns the created label with metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/labels",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueCreateLabel",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(content = CreateLabelParams, description = "Label creation parameters", content_type = "application/json"),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Label created successfully.", body = ApiResponse<IssueLabel>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty name or invalid color", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Member role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn create_label(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateLabelParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let label = service
|
||||||
|
.issue
|
||||||
|
.issue_create_label(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(label)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueMilestone;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::milestones::CreateMilestoneParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a milestone
|
||||||
|
///
|
||||||
|
/// Creates a new milestone in a repository for tracking issue progress.
|
||||||
|
/// Requires at least Member role in the repository.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - title: Milestone title (required)
|
||||||
|
/// - description: Description of the milestone (optional)
|
||||||
|
/// - due_at: Target due date (optional)
|
||||||
|
///
|
||||||
|
/// Returns the created milestone with metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/milestones",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueCreateMilestone",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = CreateMilestoneParams,
|
||||||
|
description = "Milestone creation parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Milestone created successfully. Returns the newly created milestone with metadata.", body = ApiResponse<IssueMilestone>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty title", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Member role or higher)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn create_milestone(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateMilestoneParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let milestone = service
|
||||||
|
.issue
|
||||||
|
.issue_create_milestone(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(milestone)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an issue
|
||||||
|
///
|
||||||
|
/// Soft-deletes an issue. The issue is marked as deleted but remains in the database.
|
||||||
|
/// Requires Admin role in the workspace (or issue author).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Issue is marked as deleted (soft-delete)
|
||||||
|
/// - Workspace issue count is decremented
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueDelete",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue deleted successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role or issue author)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn delete(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_delete(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Issue deleted successfully".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
pub comment_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an issue comment
|
||||||
|
///
|
||||||
|
/// Soft-deletes a comment. The comment author can delete their own comments.
|
||||||
|
/// Workspace admins can delete any comment.
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Comment is marked as deleted
|
||||||
|
/// - Issue comment count is decremented
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/comments/{comment_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueDeleteComment",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Comment deleted successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Cannot delete other users' comments (requires admin)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace, issue, or comment not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn delete_comment(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_delete_comment(&session, &path.workspace_name, path.number, path.comment_id)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Comment deleted successfully".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub repo_name: String,
|
||||||
|
pub label_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a label
|
||||||
|
///
|
||||||
|
/// Permanently removes an issue label from a repository.
|
||||||
|
/// Requires Admin role in the repository.
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Label is permanently deleted
|
||||||
|
/// - All issue-label relations using this label are removed
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/labels/{label_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueDeleteLabel",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Label deleted successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository, workspace, or label not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn delete_label(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_delete_label(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.label_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Label deleted successfully".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
/// Milestone ID (UUID)
|
||||||
|
pub milestone_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a milestone
|
||||||
|
///
|
||||||
|
/// Permanently removes a milestone from the repository.
|
||||||
|
/// Requires Admin role in the repository.
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Milestone is permanently deleted
|
||||||
|
/// - Issues attached to this milestone lose their milestone association
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/milestones/{milestone_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueDeleteMilestone",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Milestone deleted successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository, workspace, or milestone not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn delete_milestone(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_delete_milestone(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.milestone_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Milestone deleted".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get an issue by number
|
||||||
|
///
|
||||||
|
/// Returns detailed information about a specific issue, identified by workspace name and issue number.
|
||||||
|
/// Requires read access to the issue (public or workspace member).
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueGet",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue retrieved successfully. Returns complete issue with all metadata.", body = ApiResponse<Issue>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn get(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_get(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::core::IssueListFilters;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Filter by issue state ("open" or "closed")
|
||||||
|
pub state: Option<String>,
|
||||||
|
/// Filter by priority level
|
||||||
|
pub priority: Option<String>,
|
||||||
|
/// Filter by author user ID
|
||||||
|
pub author_id: Option<uuid::Uuid>,
|
||||||
|
/// Filter by assignee user ID
|
||||||
|
pub assignee_id: Option<uuid::Uuid>,
|
||||||
|
/// Filter by milestone ID
|
||||||
|
pub milestone_id: Option<uuid::Uuid>,
|
||||||
|
/// Filter by label ID
|
||||||
|
pub label_id: Option<uuid::Uuid>,
|
||||||
|
/// Maximum number of issues to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of issues to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List issues in a workspace
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of issues in the workspace, sorted by issue number (newest first).
|
||||||
|
/// Supports filtering by state, priority, author, assignee, milestone, and label.
|
||||||
|
/// Only returns issues visible to the authenticated user (public + workspace member access).
|
||||||
|
/// Requires authentication.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueList",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issues listed successfully. Returns filtered array of issue objects with metadata.", body = ApiResponse<Vec<Issue>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let filters = IssueListFilters {
|
||||||
|
state: query.state.clone(),
|
||||||
|
priority: query.priority.clone(),
|
||||||
|
author_id: query.author_id,
|
||||||
|
assignee_id: query.assignee_id,
|
||||||
|
milestone_id: query.milestone_id,
|
||||||
|
label_id: query.label_id,
|
||||||
|
};
|
||||||
|
let issues = service
|
||||||
|
.issue
|
||||||
|
.issue_list(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
filters,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issues)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueAssignee;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of assignees to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of assignees to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List assignees of an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all users assigned to the given issue.
|
||||||
|
/// Shows who is assigned, when they were assigned, and who assigned them.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/assignees",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListAssignees",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Assignees listed successfully. Returns array of assignee objects with assignment metadata.", body = ApiResponse<Vec<IssueAssignee>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_assignees(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let assignees = service
|
||||||
|
.issue
|
||||||
|
.issue_assignees(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(assignees)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueComment;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List issue comments
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of comments on an issue, sorted by creation date (oldest first).
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/comments",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListComments",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Comments listed successfully.", body = ApiResponse<Vec<IssueComment>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn list_comments(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let comments = service
|
||||||
|
.issue
|
||||||
|
.issue_comments(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(comments)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueEvent;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of events to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of events to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List issue events
|
||||||
|
///
|
||||||
|
/// Returns a chronological timeline of all events for the given issue.
|
||||||
|
/// Events include creation, updates, state changes, assignments, label changes, etc.
|
||||||
|
/// Sorted by creation date (oldest first for timeline display).
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/events",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListEvents",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Events listed successfully. Returns chronological array of event objects.", body = ApiResponse<Vec<IssueEvent>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_events(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let events = service
|
||||||
|
.issue
|
||||||
|
.issue_list_events(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(events)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueLabelRelation;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of label relations to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of label relations to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List labels assigned to an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all label relations for the given issue.
|
||||||
|
/// Shows which labels are attached to the issue, with assignment metadata.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/labels",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListLabelRelations",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Label relations listed successfully. Returns array of label relation objects with metadata.", body = ApiResponse<Vec<IssueLabelRelation>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_issue_labels(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let rels = service
|
||||||
|
.issue
|
||||||
|
.issue_label_relations(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(rels)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueLabel;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub repo_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List labels in a repository
|
||||||
|
///
|
||||||
|
/// Returns all issue labels defined in the repository, sorted alphabetically.
|
||||||
|
/// Requires read access to the repository.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/labels",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListLabels",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Labels listed successfully.", body = ApiResponse<Vec<IssueLabel>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn list_labels(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let labels = service
|
||||||
|
.issue
|
||||||
|
.issue_labels(&session, &path.workspace_name, &path.repo_name)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(labels)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueMilestone;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of milestones to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of milestones to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List milestones in a repository
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of milestones in the repository, sorted by state (open first) then by due date.
|
||||||
|
/// Includes milestone metadata such as title, description, state, due date, and progress.
|
||||||
|
/// Requires read access to the repository.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/milestones",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListMilestones",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Milestones listed successfully. Returns array of milestone objects with metadata.", body = ApiResponse<Vec<IssueMilestone>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to access this repository", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_milestones(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let milestones = service
|
||||||
|
.issue
|
||||||
|
.issue_milestones(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(milestones)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, utoipa::ToSchema)]
|
||||||
|
pub struct LockIssueParams {
|
||||||
|
/// Whether to lock (true) or unlock (false) the issue
|
||||||
|
pub locked: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lock or unlock an issue
|
||||||
|
///
|
||||||
|
/// Locks or unlocks conversation on an issue. When locked, only users with write access can comment.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Returns the updated issue with lock status.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/lock",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueLock",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = LockIssueParams,
|
||||||
|
description = "Lock/unlock parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue lock status updated successfully.", body = ApiResponse<Issue>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to manage this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn lock(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<LockIssueParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_lock(&session, &path.workspace_name, path.number, params.locked)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
pub mod assign_issue;
|
||||||
|
pub mod assign_label;
|
||||||
|
pub mod close;
|
||||||
|
pub mod create;
|
||||||
|
pub mod create_comment;
|
||||||
|
pub mod create_label;
|
||||||
|
pub mod create_milestone;
|
||||||
|
pub mod delete;
|
||||||
|
pub mod delete_comment;
|
||||||
|
pub mod delete_label;
|
||||||
|
pub mod delete_milestone;
|
||||||
|
pub mod get;
|
||||||
|
pub mod list;
|
||||||
|
pub mod list_assignees;
|
||||||
|
pub mod list_comments;
|
||||||
|
pub mod list_events;
|
||||||
|
pub mod list_issue_labels;
|
||||||
|
pub mod list_labels;
|
||||||
|
pub mod list_milestones;
|
||||||
|
pub mod lock;
|
||||||
|
pub mod pr_relations;
|
||||||
|
pub mod reactions;
|
||||||
|
pub mod reopen;
|
||||||
|
pub mod repo_relations;
|
||||||
|
pub mod subscribers;
|
||||||
|
pub mod templates;
|
||||||
|
pub mod transfer;
|
||||||
|
pub mod unassign_issue;
|
||||||
|
pub mod unassign_label;
|
||||||
|
pub mod update;
|
||||||
|
pub mod update_comment;
|
||||||
|
pub mod update_label;
|
||||||
|
pub mod update_milestone;
|
||||||
|
|
||||||
|
use actix_web::web;
|
||||||
|
|
||||||
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
|
cfg.service(
|
||||||
|
web::scope("/issues")
|
||||||
|
// Core
|
||||||
|
.route("", web::get().to(list::list))
|
||||||
|
.route("", web::post().to(create::create))
|
||||||
|
.route("/{number}", web::get().to(get::get))
|
||||||
|
.route("/{number}", web::put().to(update::update))
|
||||||
|
.route("/{number}", web::delete().to(delete::delete))
|
||||||
|
.route("/{number}/close", web::post().to(close::close))
|
||||||
|
.route("/{number}/reopen", web::post().to(reopen::reopen))
|
||||||
|
.route("/{number}/lock", web::put().to(lock::lock))
|
||||||
|
.route("/{number}/transfer", web::post().to(transfer::transfer))
|
||||||
|
// Comments
|
||||||
|
.route(
|
||||||
|
"/{number}/comments",
|
||||||
|
web::get().to(list_comments::list_comments),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/comments",
|
||||||
|
web::post().to(create_comment::create_comment),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/comments/{comment_id}",
|
||||||
|
web::put().to(update_comment::update_comment),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/comments/{comment_id}",
|
||||||
|
web::delete().to(delete_comment::delete_comment),
|
||||||
|
)
|
||||||
|
// Labels (issue-level)
|
||||||
|
.route(
|
||||||
|
"/{number}/labels",
|
||||||
|
web::get().to(list_issue_labels::list_issue_labels),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/labels/{label_id}",
|
||||||
|
web::post().to(assign_label::assign_label),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/labels/{label_id}",
|
||||||
|
web::delete().to(unassign_label::unassign_label),
|
||||||
|
)
|
||||||
|
// Assignees
|
||||||
|
.route(
|
||||||
|
"/{number}/assignees",
|
||||||
|
web::get().to(list_assignees::list_assignees),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/assignees/{user_id}",
|
||||||
|
web::post().to(assign_issue::assign_issue),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/assignees/{user_id}",
|
||||||
|
web::delete().to(unassign_issue::unassign_issue),
|
||||||
|
)
|
||||||
|
// Events
|
||||||
|
.route("/{number}/events", web::get().to(list_events::list_events))
|
||||||
|
// Reactions
|
||||||
|
.route(
|
||||||
|
"/{number}/reactions",
|
||||||
|
web::get().to(reactions::list_reactions),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/reactions",
|
||||||
|
web::post().to(reactions::add_reaction),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/reactions/{reaction_id}",
|
||||||
|
web::delete().to(reactions::remove_reaction),
|
||||||
|
)
|
||||||
|
// Subscribers
|
||||||
|
.route(
|
||||||
|
"/{number}/subscribers",
|
||||||
|
web::get().to(subscribers::list_subscribers),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/subscribe",
|
||||||
|
web::post().to(subscribers::subscribe),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{number}/subscribe",
|
||||||
|
web::delete().to(subscribers::unsubscribe),
|
||||||
|
)
|
||||||
|
.route("/{number}/mute", web::put().to(subscribers::mute))
|
||||||
|
// Repo relations
|
||||||
|
.route(
|
||||||
|
"/{number}/repos",
|
||||||
|
web::get().to(repo_relations::list_repo_relations),
|
||||||
|
)
|
||||||
|
.route("/{number}/repos", web::post().to(repo_relations::link_repo))
|
||||||
|
.route(
|
||||||
|
"/{number}/repos/{relation_id}",
|
||||||
|
web::delete().to(repo_relations::unlink_repo),
|
||||||
|
)
|
||||||
|
// PR relations
|
||||||
|
.route(
|
||||||
|
"/{number}/prs",
|
||||||
|
web::get().to(pr_relations::list_pr_relations),
|
||||||
|
)
|
||||||
|
.route("/{number}/prs", web::post().to(pr_relations::link_pr))
|
||||||
|
.route(
|
||||||
|
"/{number}/prs/{relation_id}",
|
||||||
|
web::delete().to(pr_relations::unlink_pr),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_repo_level(cfg: &mut web::ServiceConfig) {
|
||||||
|
cfg.service(
|
||||||
|
web::scope("/issues")
|
||||||
|
.route("/labels", web::get().to(list_labels::list_labels))
|
||||||
|
.route("/labels", web::post().to(create_label::create_label))
|
||||||
|
.route(
|
||||||
|
"/labels/{label_id}",
|
||||||
|
web::put().to(update_label::update_label),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/labels/{label_id}",
|
||||||
|
web::delete().to(delete_label::delete_label),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/milestones",
|
||||||
|
web::get().to(list_milestones::list_milestones),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/milestones",
|
||||||
|
web::post().to(create_milestone::create_milestone),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/milestones/{milestone_id}",
|
||||||
|
web::put().to(update_milestone::update_milestone),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/milestones/{milestone_id}",
|
||||||
|
web::delete().to(delete_milestone::delete_milestone),
|
||||||
|
)
|
||||||
|
.route("/templates", web::get().to(templates::list_templates))
|
||||||
|
.route("/templates", web::post().to(templates::create_template))
|
||||||
|
.route(
|
||||||
|
"/templates/{template_id}",
|
||||||
|
web::put().to(templates::update_template),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/templates/{template_id}",
|
||||||
|
web::delete().to(templates::delete_template),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssuePrRelation;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::pr_relations::LinkPrParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of relations to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of relations to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List pull request relations for an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all pull requests linked to the given issue.
|
||||||
|
/// Shows relation type (closes, references, depends_on, etc.) and link metadata.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/prs",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListPrRelations",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "PR relations listed successfully. Returns array of PR relation objects.", body = ApiResponse<Vec<IssuePrRelation>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_pr_relations(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let relations = service
|
||||||
|
.issue
|
||||||
|
.issue_pr_relations(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(relations)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link a pull request to an issue
|
||||||
|
///
|
||||||
|
/// Creates a relation between the given issue and a pull request.
|
||||||
|
/// Commonly used to mark a PR as closing or referencing an issue.
|
||||||
|
/// Requires write access to the issue.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - pull_request_id: Pull request ID (UUID) to link
|
||||||
|
/// - relation_type: Relation type ("closes", "references", "depends_on", default: "references")
|
||||||
|
///
|
||||||
|
/// Returns the created relation.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/prs",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueLinkPr",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = LinkPrParams,
|
||||||
|
description = "Link pull request parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Pull request linked successfully. Returns the created relation.", body = ApiResponse<IssuePrRelation>),
|
||||||
|
(status = 400, description = "Invalid parameters: invalid relation type", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue or pull request not found", body = ApiErrorResponse),
|
||||||
|
(status = 409, description = "Pull request is already linked to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn link_pr(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<LinkPrParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let relation = service
|
||||||
|
.issue
|
||||||
|
.issue_link_pr(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(relation)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct RelationPathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// Relation ID (UUID)
|
||||||
|
pub relation_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlink a pull request from an issue
|
||||||
|
///
|
||||||
|
/// Removes a pull request relation from the given issue.
|
||||||
|
/// Requires write access to the issue.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/prs/{relation_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUnlinkPr",
|
||||||
|
params(RelationPathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Pull request unlinked successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "PR relation not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn unlink_pr(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<RelationPathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_unlink_pr(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
path.relation_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("PR unlinked".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueReaction;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::reactions::CreateIssueReactionParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of reactions to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of reactions to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List reactions on an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all emoji reactions on the given issue.
|
||||||
|
/// Includes reaction content, target type, and user who added each reaction.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/reactions",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListReactions",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Reactions listed successfully. Returns array of reaction objects.", body = ApiResponse<Vec<IssueReaction>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_reactions(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let reactions = service
|
||||||
|
.issue
|
||||||
|
.issue_reactions(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(reactions)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a reaction to an issue
|
||||||
|
///
|
||||||
|
/// Adds an emoji reaction to the given issue.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - content: Reaction content (e.g., "👍", "❤️", "🎉")
|
||||||
|
/// - target_type: Target type for the reaction (defaults to "Issue")
|
||||||
|
/// - target_id: Target ID for reactions on specific comments (optional)
|
||||||
|
///
|
||||||
|
/// Returns the created reaction.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/reactions",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueAddReaction",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = CreateIssueReactionParams,
|
||||||
|
description = "Reaction creation parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Reaction added successfully. Returns the created reaction.", body = ApiResponse<IssueReaction>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty content or invalid target type", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn add_reaction(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateIssueReactionParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let reaction = service
|
||||||
|
.issue
|
||||||
|
.issue_add_reaction(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(reaction)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct ReactionPathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// Reaction ID (UUID)
|
||||||
|
pub reaction_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a reaction from an issue
|
||||||
|
///
|
||||||
|
/// Removes a previously added reaction. Only the user who added the reaction can remove it.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/reactions/{reaction_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueRemoveReaction",
|
||||||
|
params(ReactionPathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Reaction removed successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Cannot remove another user's reaction", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Reaction not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn remove_reaction(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<ReactionPathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_remove_reaction(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
path.reaction_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Reaction removed".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reopen an issue
|
||||||
|
///
|
||||||
|
/// Reopens a closed issue. The issue state changes back to "open" and closed metadata is cleared.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Returns the reopened issue with updated metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/reopen",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueReopen",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue reopened successfully. Returns the reopened issue with updated metadata.", body = ApiResponse<Issue>),
|
||||||
|
(status = 400, description = "Issue is not closed", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to reopen this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn reopen(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_reopen(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueRepoRelation;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::repo_relations::LinkRepoParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of relations to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of relations to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List repository relations for an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all repositories linked to the given issue.
|
||||||
|
/// Shows relation type (references, duplicates, blocks, etc.) and link metadata.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/repos",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListRepoRelations",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Repository relations listed successfully. Returns array of relation objects.", body = ApiResponse<Vec<IssueRepoRelation>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_repo_relations(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let relations = service
|
||||||
|
.issue
|
||||||
|
.issue_repo_relations(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(relations)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link a repository to an issue
|
||||||
|
///
|
||||||
|
/// Creates a relation between the given issue and a repository.
|
||||||
|
/// Requires write access to the issue.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - repo_id: Repository ID (UUID) to link
|
||||||
|
/// - relation_type: Relation type ("references", "duplicates", "blocks", "depends_on", default: "references")
|
||||||
|
///
|
||||||
|
/// Returns the created relation.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/repos",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueLinkRepo",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = LinkRepoParams,
|
||||||
|
description = "Link repository parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Repository linked successfully. Returns the created relation.", body = ApiResponse<IssueRepoRelation>),
|
||||||
|
(status = 400, description = "Invalid parameters: invalid relation type", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue or repository not found", body = ApiErrorResponse),
|
||||||
|
(status = 409, description = "Repository is already linked to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn link_repo(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<LinkRepoParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let relation = service
|
||||||
|
.issue
|
||||||
|
.issue_link_repo(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(relation)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct RelationPathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// Relation ID (UUID)
|
||||||
|
pub relation_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlink a repository from an issue
|
||||||
|
///
|
||||||
|
/// Removes a repository relation from the given issue.
|
||||||
|
/// Requires write access to the issue.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/repos/{relation_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUnlinkRepo",
|
||||||
|
params(RelationPathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Repository unlinked successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository relation not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn unlink_repo(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<RelationPathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_unlink_repo(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
path.relation_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Repo unlinked".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueSubscriber;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of subscribers to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of subscribers to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List subscribers of an issue
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all users subscribed to the given issue.
|
||||||
|
/// Shows who receives notifications and their subscription reason (author, assignee, manual).
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/subscribers",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListSubscribers",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Subscribers listed successfully. Returns array of subscriber objects.", body = ApiResponse<Vec<IssueSubscriber>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_subscribers(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let subscribers = service
|
||||||
|
.issue
|
||||||
|
.issue_subscribers(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(subscribers)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subscribe to an issue
|
||||||
|
///
|
||||||
|
/// Subscribes the authenticated user to the given issue to receive notifications.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - User is added as a subscriber with "manual" reason
|
||||||
|
/// - User receives notifications for all issue activity
|
||||||
|
///
|
||||||
|
/// Returns the created subscription record.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/subscribe",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueSubscribe",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Subscribed successfully. Returns the subscription record.", body = ApiResponse<IssueSubscriber>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to view this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 409, description = "Already subscribed to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn subscribe(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let sub = service
|
||||||
|
.issue
|
||||||
|
.issue_subscribe(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(sub)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unsubscribe from an issue
|
||||||
|
///
|
||||||
|
/// Removes the authenticated user's subscription to the given issue.
|
||||||
|
/// Stops all notifications for this issue.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/subscribe",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUnsubscribe",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Unsubscribed successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Not currently subscribed to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn unsubscribe(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_unsubscribe(&session, &path.workspace_name, path.number)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Unsubscribed".to_string())))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, utoipa::ToSchema)]
|
||||||
|
pub struct MuteIssueParams {
|
||||||
|
/// Whether to mute (true) or unmute (false) notifications
|
||||||
|
pub muted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mute or unmute issue notifications
|
||||||
|
///
|
||||||
|
/// Mutes or unmutes notifications for the given issue without unsubscribing.
|
||||||
|
/// Requires an active subscription to the issue.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/mute",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueMute",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = MuteIssueParams,
|
||||||
|
description = "Mute/unmute parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Mute status updated successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Not currently subscribed to this issue", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn mute(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<MuteIssueParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_mute(&session, &path.workspace_name, path.number, params.muted)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Mute status updated".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueTemplate;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::templates::{CreateTemplateParams, UpdateTemplateParams};
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct QueryParams {
|
||||||
|
/// Maximum number of templates to return (default: 50, max: 100)
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
/// Number of templates to skip for pagination (default: 0)
|
||||||
|
pub offset: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List issue templates in a repository
|
||||||
|
///
|
||||||
|
/// Returns a paginated list of all active issue templates in the repository.
|
||||||
|
/// Templates provide pre-filled content for creating new issues.
|
||||||
|
/// Sorted alphabetically by name.
|
||||||
|
/// Requires read access to the repository.
|
||||||
|
#[utoipa::path(
|
||||||
|
get,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/templates",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueListTemplates",
|
||||||
|
params(PathParams, QueryParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Templates listed successfully. Returns array of template objects.", body = ApiResponse<Vec<IssueTemplate>>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to access this repository", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn list_templates(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
query: web::Query<QueryParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let templates = service
|
||||||
|
.issue
|
||||||
|
.issue_templates(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
query.limit.unwrap_or(50),
|
||||||
|
query.offset.unwrap_or(0),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(templates)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an issue template
|
||||||
|
///
|
||||||
|
/// Creates a new issue template in the repository.
|
||||||
|
/// Requires at least Member role in the repository.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// - name: Template name (required)
|
||||||
|
/// - description: Template description (optional)
|
||||||
|
/// - title_template: Default title for issues (optional, supports placeholders)
|
||||||
|
/// - body_template: Default body content in markdown (required)
|
||||||
|
/// - labels: List of label names to auto-apply (optional)
|
||||||
|
///
|
||||||
|
/// Returns the created template with metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/templates",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueCreateTemplate",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = CreateTemplateParams,
|
||||||
|
description = "Template creation parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 201, description = "Template created successfully. Returns the newly created template.", body = ApiResponse<IssueTemplate>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty name or body template", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Member role or higher)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository or workspace not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn create_template(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<CreateTemplateParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let template = service
|
||||||
|
.issue
|
||||||
|
.issue_create_template(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Created().json(ApiResponse::new(template)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct TemplatePathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
/// Template ID (UUID)
|
||||||
|
pub template_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update an issue template
|
||||||
|
///
|
||||||
|
/// Updates an existing issue template's metadata and content.
|
||||||
|
/// Requires Admin role in the repository.
|
||||||
|
///
|
||||||
|
/// All fields are optional; only provided fields are updated.
|
||||||
|
/// Returns the updated template.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/templates/{template_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUpdateTemplate",
|
||||||
|
params(TemplatePathParams),
|
||||||
|
request_body(
|
||||||
|
content = UpdateTemplateParams,
|
||||||
|
description = "Template update parameters (all fields optional)",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Template updated successfully. Returns the updated template.", body = ApiResponse<IssueTemplate>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository, workspace, or template not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn update_template(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<TemplatePathParams>,
|
||||||
|
params: web::Json<UpdateTemplateParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let template = service
|
||||||
|
.issue
|
||||||
|
.issue_update_template(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.template_id,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(template)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an issue template
|
||||||
|
///
|
||||||
|
/// Permanently removes an issue template from the repository.
|
||||||
|
/// Requires Admin role in the repository.
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/templates/{template_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueDeleteTemplate",
|
||||||
|
params(TemplatePathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Template deleted successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Template not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn delete_template(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<TemplatePathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_delete_template(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.template_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Template deleted".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, utoipa::ToSchema)]
|
||||||
|
pub struct TransferIssueParams {
|
||||||
|
/// Target workspace name to transfer the issue to
|
||||||
|
pub target_workspace_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transfer an issue to another workspace
|
||||||
|
///
|
||||||
|
/// Moves an issue from the current workspace to a different workspace.
|
||||||
|
/// Requires Admin role in both the source and target workspaces.
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Issue is transferred to the target workspace with a new number
|
||||||
|
/// - Source workspace issue count is decremented
|
||||||
|
/// - Target workspace issue count is incremented
|
||||||
|
///
|
||||||
|
/// Returns the transferred issue with updated workspace and number.
|
||||||
|
#[utoipa::path(
|
||||||
|
post,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/transfer",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueTransfer",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = TransferIssueParams,
|
||||||
|
description = "Transfer parameters",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue transferred successfully. Returns the issue with new workspace assignment.", body = ApiResponse<Issue>),
|
||||||
|
(status = 400, description = "Invalid target workspace", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions in source or target workspace", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace or issue not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn transfer(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<TransferIssueParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_transfer(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
¶ms.target_workspace_name,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// User ID (UUID) to unassign
|
||||||
|
pub user_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unassign a user from an issue
|
||||||
|
///
|
||||||
|
/// Removes a user from the issue's assignee list.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - User is removed from the issue's assignees
|
||||||
|
/// - Issue assignee count is decremented
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/assignees/{user_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUnassign",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "User unassigned successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "User is not assigned to this issue or not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn unassign_issue(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_unassign(&session, &path.workspace_name, path.number, path.user_id)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("User unassigned".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
/// Label ID (UUID) to unassign
|
||||||
|
pub label_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unassign a label from an issue
|
||||||
|
///
|
||||||
|
/// Removes a label from the given issue.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// Effects:
|
||||||
|
/// - Label relation is removed from the issue
|
||||||
|
/// - Issue label count is decremented
|
||||||
|
///
|
||||||
|
/// Returns success message on completion.
|
||||||
|
#[utoipa::path(
|
||||||
|
delete,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/labels/{label_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUnassignLabel",
|
||||||
|
params(PathParams),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Label unassigned successfully.", body = ApiResponse<String>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Label is not assigned to this issue or not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn unassign_label(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
service
|
||||||
|
.issue
|
||||||
|
.issue_unassign_label(&session, &path.workspace_name, path.number, path.label_id)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Label unassigned".to_string())))
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::Issue;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::core::UpdateIssueParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Issue number (unique within the workspace)
|
||||||
|
pub number: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update an issue
|
||||||
|
///
|
||||||
|
/// Updates an existing issue's metadata such as title, body, priority, visibility, due date, and milestone.
|
||||||
|
/// Requires write access to the issue (author or workspace member).
|
||||||
|
///
|
||||||
|
/// All fields are optional; only provided fields are updated.
|
||||||
|
/// Returns the updated issue with full metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUpdate",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = UpdateIssueParams,
|
||||||
|
description = "Issue update parameters (all fields optional)",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Issue updated successfully. Returns the updated issue with full metadata.", body = ApiResponse<Issue>),
|
||||||
|
(status = 400, description = "Invalid parameters: invalid priority, visibility, or milestone", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions to edit this issue", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace, issue, or referenced resource not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn update(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<UpdateIssueParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let issue = service
|
||||||
|
.issue
|
||||||
|
.issue_update(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(issue)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueComment;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::comments::UpdateCommentParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub number: i64,
|
||||||
|
pub comment_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update an issue comment
|
||||||
|
///
|
||||||
|
/// Updates the body of an existing comment. Only the comment author can update their own comments.
|
||||||
|
/// Requires read access to the issue.
|
||||||
|
///
|
||||||
|
/// Returns the updated comment with edit timestamp.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/issues/{number}/comments/{comment_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUpdateComment",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(content = UpdateCommentParams, description = "Comment update parameters", content_type = "application/json"),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Comment updated successfully.", body = ApiResponse<IssueComment>),
|
||||||
|
(status = 400, description = "Invalid parameters: empty body", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Cannot edit other users' comments", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Workspace, issue, or comment not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn update_comment(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<UpdateCommentParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let comment = service
|
||||||
|
.issue
|
||||||
|
.issue_update_comment(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
path.number,
|
||||||
|
path.comment_id,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(comment)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueLabel;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::labels::UpdateLabelParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
pub workspace_name: String,
|
||||||
|
pub repo_name: String,
|
||||||
|
pub label_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update a label
|
||||||
|
///
|
||||||
|
/// Updates an existing issue label's name, color, or description.
|
||||||
|
/// Requires Admin role in the repository.
|
||||||
|
///
|
||||||
|
/// All fields are optional; only provided fields are updated.
|
||||||
|
/// Returns the updated label.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/labels/{label_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUpdateLabel",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(content = UpdateLabelParams, description = "Label update parameters (all fields optional)", content_type = "application/json"),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Label updated successfully.", body = ApiResponse<IssueLabel>),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Admin role)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository, workspace, or label not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(("session_cookie" = []))
|
||||||
|
)]
|
||||||
|
pub async fn update_label(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<UpdateLabelParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let label = service
|
||||||
|
.issue
|
||||||
|
.issue_update_label(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.label_id,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(label)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
use actix_web::{HttpResponse, web};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
|
use crate::error::AppError;
|
||||||
|
use crate::models::issues::IssueMilestone;
|
||||||
|
use crate::service::AppService;
|
||||||
|
use crate::service::issues::milestones::UpdateMilestoneParams;
|
||||||
|
use crate::session::Session;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
pub struct PathParams {
|
||||||
|
/// Workspace name (unique identifier)
|
||||||
|
pub workspace_name: String,
|
||||||
|
/// Repository name (unique within the workspace)
|
||||||
|
pub repo_name: String,
|
||||||
|
/// Milestone ID (UUID)
|
||||||
|
pub milestone_id: uuid::Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update a milestone
|
||||||
|
///
|
||||||
|
/// Updates an existing milestone's metadata. Can also close or reopen the milestone via the state field.
|
||||||
|
/// Requires at least Member role in the repository.
|
||||||
|
///
|
||||||
|
/// Updatable fields:
|
||||||
|
/// - title: Milestone title (optional)
|
||||||
|
/// - description: Description (optional)
|
||||||
|
/// - due_at: Target due date (optional)
|
||||||
|
/// - state: State ("open" or "closed") for closing/reopening the milestone (optional)
|
||||||
|
///
|
||||||
|
/// All fields are optional; only provided fields are updated.
|
||||||
|
/// Returns the updated milestone with full metadata.
|
||||||
|
#[utoipa::path(
|
||||||
|
put,
|
||||||
|
path = "/api/v1/workspaces/{workspace_name}/repos/{repo_name}/issues/milestones/{milestone_id}",
|
||||||
|
tag = "Issues",
|
||||||
|
operation_id = "issueUpdateMilestone",
|
||||||
|
params(PathParams),
|
||||||
|
request_body(
|
||||||
|
content = UpdateMilestoneParams,
|
||||||
|
description = "Milestone update parameters (all fields optional)",
|
||||||
|
content_type = "application/json"
|
||||||
|
),
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Milestone updated successfully. Returns the updated milestone with full metadata.", body = ApiResponse<IssueMilestone>),
|
||||||
|
(status = 400, description = "Invalid parameters", body = ApiErrorResponse),
|
||||||
|
(status = 401, description = "Authentication required or session expired", body = ApiErrorResponse),
|
||||||
|
(status = 403, description = "Insufficient permissions (requires Member role or higher)", body = ApiErrorResponse),
|
||||||
|
(status = 404, description = "Repository, workspace, or milestone not found", body = ApiErrorResponse),
|
||||||
|
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("session_cookie" = [])
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub async fn update_milestone(
|
||||||
|
service: web::Data<AppService>,
|
||||||
|
session: Session,
|
||||||
|
path: web::Path<PathParams>,
|
||||||
|
params: web::Json<UpdateMilestoneParams>,
|
||||||
|
) -> Result<HttpResponse, AppError> {
|
||||||
|
let milestone = service
|
||||||
|
.issue
|
||||||
|
.issue_update_milestone(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.milestone_id,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(HttpResponse::Ok().json(ApiResponse::new(milestone)))
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod issue;
|
||||||
pub mod openapi;
|
pub mod openapi;
|
||||||
pub mod repo;
|
pub mod repo;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
pub mod user;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
|
|||||||
+217
-8
@@ -4,18 +4,28 @@ use crate::api::auth::regenerate_2fa_backup_codes::{
|
|||||||
Regenerate2FABackupCodesRequest, Regenerate2FABackupCodesResponse,
|
Regenerate2FABackupCodesRequest, Regenerate2FABackupCodesResponse,
|
||||||
};
|
};
|
||||||
use crate::api::auth::register::RegisterResponse;
|
use crate::api::auth::register::RegisterResponse;
|
||||||
use crate::api::response::{ApiEmptyResponse, ApiErrorResponse, ApiResponse};
|
use crate::api::issue::lock::LockIssueParams;
|
||||||
|
use crate::api::issue::subscribers::MuteIssueParams;
|
||||||
|
use crate::api::issue::transfer::TransferIssueParams;
|
||||||
use crate::api::repo::accept_invitation::AcceptInvitationParams;
|
use crate::api::repo::accept_invitation::AcceptInvitationParams;
|
||||||
use crate::api::repo::set_branch_protection::SetBranchProtectionParams;
|
use crate::api::repo::set_branch_protection::SetBranchProtectionParams;
|
||||||
use crate::api::repo::transfer_owner::TransferOwnerParams;
|
use crate::api::repo::transfer_owner::TransferOwnerParams;
|
||||||
use crate::service::repo::watches::WatchParams;
|
use crate::api::response::{ApiEmptyResponse, ApiErrorResponse, ApiResponse};
|
||||||
use crate::api::workspace::accept_invitation::AcceptInvitationRequest;
|
use crate::api::workspace::accept_invitation::AcceptInvitationRequest;
|
||||||
use crate::api::workspace::review_approval::ReviewApprovalRequest;
|
use crate::api::workspace::review_approval::ReviewApprovalRequest;
|
||||||
use crate::api::workspace::transfer_owner::TransferOwnerRequest;
|
use crate::api::workspace::transfer_owner::TransferOwnerRequest;
|
||||||
|
use crate::models::issues::{
|
||||||
|
Issue, IssueAssignee, IssueComment, IssueEvent, IssueLabel, IssueLabelRelation, IssueMilestone,
|
||||||
|
IssuePrRelation, IssueReaction, IssueRepoRelation, IssueSubscriber, IssueTemplate,
|
||||||
|
};
|
||||||
use crate::models::repos::{
|
use crate::models::repos::{
|
||||||
BranchProtectionRule, Repo, RepoBranch, RepoCommitComment,
|
BranchProtectionRule, Repo, RepoBranch, RepoCommitComment, RepoCommitStatus, RepoDeployKey,
|
||||||
RepoCommitStatus, RepoDeployKey, RepoFork, RepoInvitation, RepoMember, RepoRelease,
|
RepoFork, RepoInvitation, RepoMember, RepoRelease, RepoStar, RepoStats, RepoTag, RepoWatch,
|
||||||
RepoStar, RepoStats, RepoTag, RepoWatch, RepoWebhook,
|
RepoWebhook,
|
||||||
|
};
|
||||||
|
use crate::models::users::{
|
||||||
|
User, UserAppearance, UserDevice, UserGpgKey, UserNotifySetting, UserProfile, UserSecurityLog,
|
||||||
|
UserSshKey,
|
||||||
};
|
};
|
||||||
use crate::models::workspaces::{
|
use crate::models::workspaces::{
|
||||||
Workspace, WorkspaceAuditLog, WorkspaceBilling, WorkspaceCustomBranding, WorkspaceDomain,
|
Workspace, WorkspaceAuditLog, WorkspaceBilling, WorkspaceCustomBranding, WorkspaceDomain,
|
||||||
@@ -34,6 +44,14 @@ use crate::service::auth::rsa::RsaResponse;
|
|||||||
use crate::service::auth::totp::{
|
use crate::service::auth::totp::{
|
||||||
Disable2FAParams, Enable2FAResponse, Get2FAStatusResponse, Verify2FAParams,
|
Disable2FAParams, Enable2FAResponse, Get2FAStatusResponse, Verify2FAParams,
|
||||||
};
|
};
|
||||||
|
use crate::service::issues::comments::{CreateCommentParams, UpdateCommentParams};
|
||||||
|
use crate::service::issues::core::{CreateIssueParams, IssueListFilters, UpdateIssueParams};
|
||||||
|
use crate::service::issues::labels::{CreateLabelParams, UpdateLabelParams};
|
||||||
|
use crate::service::issues::milestones::{CreateMilestoneParams, UpdateMilestoneParams};
|
||||||
|
use crate::service::issues::pr_relations::LinkPrParams;
|
||||||
|
use crate::service::issues::reactions::CreateIssueReactionParams;
|
||||||
|
use crate::service::issues::repo_relations::LinkRepoParams;
|
||||||
|
use crate::service::issues::templates::{CreateTemplateParams, UpdateTemplateParams};
|
||||||
use crate::service::repo::branches::CreateBranchParams;
|
use crate::service::repo::branches::CreateBranchParams;
|
||||||
use crate::service::repo::commit_status::{CreateCommitCommentParams, CreateCommitStatusParams};
|
use crate::service::repo::commit_status::{CreateCommitCommentParams, CreateCommitStatusParams};
|
||||||
use crate::service::repo::core::{CreateRepoParams, UpdateRepoParams};
|
use crate::service::repo::core::{CreateRepoParams, UpdateRepoParams};
|
||||||
@@ -46,6 +64,18 @@ use crate::service::repo::protection::{
|
|||||||
};
|
};
|
||||||
use crate::service::repo::releases::{CreateReleaseParams, UpdateReleaseParams};
|
use crate::service::repo::releases::{CreateReleaseParams, UpdateReleaseParams};
|
||||||
use crate::service::repo::tags::CreateTagParams;
|
use crate::service::repo::tags::CreateTagParams;
|
||||||
|
use crate::service::repo::watches::WatchParams;
|
||||||
|
use crate::service::repo::webhooks::{
|
||||||
|
CreateWebhookParams as RepoCreateWebhookParams, UpdateWebhookParams as RepoUpdateWebhookParams,
|
||||||
|
};
|
||||||
|
use crate::service::user::account::{
|
||||||
|
UpdateUserAccountParams, UploadUserAvatarParams, UserAvatarResponse,
|
||||||
|
};
|
||||||
|
use crate::service::user::appearance::UpdateUserAppearanceParams;
|
||||||
|
use crate::service::user::keys::{AddGpgKeyParams, AddSshKeyParams};
|
||||||
|
use crate::service::user::notify::UpdateUserNotifySettingParams;
|
||||||
|
use crate::service::user::profile::UpdateUserProfileParams;
|
||||||
|
use crate::service::user::security::{UserOAuthInfo, UserPersonalAccessTokenInfo, UserSessionInfo};
|
||||||
use crate::service::workspace::approvals::RequestApprovalParams;
|
use crate::service::workspace::approvals::RequestApprovalParams;
|
||||||
use crate::service::workspace::billing::UpdateBillingParams;
|
use crate::service::workspace::billing::UpdateBillingParams;
|
||||||
use crate::service::workspace::branding::UpdateBrandingParams;
|
use crate::service::workspace::branding::UpdateBrandingParams;
|
||||||
@@ -66,8 +96,10 @@ use crate::service::workspace::webhooks::{CreateWebhookParams, UpdateWebhookPara
|
|||||||
),
|
),
|
||||||
tags(
|
tags(
|
||||||
(name = "Auth", description = "Authentication, registration, session and email security endpoints."),
|
(name = "Auth", description = "Authentication, registration, session and email security endpoints."),
|
||||||
|
(name = "User", description = "User account management, profile, appearance, notification settings, SSH/GPG keys, sessions, devices, OAuth accounts, security logs, and personal access tokens."),
|
||||||
(name = "Workspaces", description = "Workspace CRUD, archiving, ownership transfer, and avatar management."),
|
(name = "Workspaces", description = "Workspace CRUD, archiving, ownership transfer, and avatar management."),
|
||||||
(name = "Repos", description = "Repository management including branches, tags, releases, forks, stars, watches, members, invitations, deploy keys, webhooks, protection rules, commit statuses, and statistics."),
|
(name = "Repos", description = "Repository management including branches, tags, releases, forks, stars, watches, members, invitations, deploy keys, webhooks, protection rules, commit statuses, and statistics."),
|
||||||
|
(name = "Issues", description = "Issue tracking, comments, labels, milestones, assignees, events, reactions, subscribers, templates, and cross-references with repos and pull requests."),
|
||||||
),
|
),
|
||||||
paths(
|
paths(
|
||||||
// Auth
|
// Auth
|
||||||
@@ -88,6 +120,89 @@ use crate::service::workspace::webhooks::{CreateWebhookParams, UpdateWebhookPara
|
|||||||
crate::api::auth::verify_2fa::handle,
|
crate::api::auth::verify_2fa::handle,
|
||||||
crate::api::auth::disable_2fa::handle,
|
crate::api::auth::disable_2fa::handle,
|
||||||
crate::api::auth::regenerate_2fa_backup_codes::handle,
|
crate::api::auth::regenerate_2fa_backup_codes::handle,
|
||||||
|
// User
|
||||||
|
crate::api::user::get_account::get_account,
|
||||||
|
crate::api::user::update_account::update_account,
|
||||||
|
crate::api::user::upload_avatar::upload_avatar,
|
||||||
|
crate::api::user::delete_account::delete_account,
|
||||||
|
crate::api::user::get_appearance::get_appearance,
|
||||||
|
crate::api::user::update_appearance::update_appearance,
|
||||||
|
crate::api::user::get_profile::get_profile,
|
||||||
|
crate::api::user::update_profile::update_profile,
|
||||||
|
crate::api::user::get_notifications::get_notifications,
|
||||||
|
crate::api::user::update_notifications::update_notifications,
|
||||||
|
crate::api::user::list_ssh_keys::list_ssh_keys,
|
||||||
|
crate::api::user::add_ssh_key::add_ssh_key,
|
||||||
|
crate::api::user::delete_ssh_key::delete_ssh_key,
|
||||||
|
crate::api::user::list_gpg_keys::list_gpg_keys,
|
||||||
|
crate::api::user::add_gpg_key::add_gpg_key,
|
||||||
|
crate::api::user::delete_gpg_key::delete_gpg_key,
|
||||||
|
crate::api::user::list_sessions::list_sessions,
|
||||||
|
crate::api::user::revoke_session::revoke_session,
|
||||||
|
crate::api::user::list_devices::list_devices,
|
||||||
|
crate::api::user::delete_device::delete_device,
|
||||||
|
crate::api::user::list_oauth_accounts::list_oauth_accounts,
|
||||||
|
crate::api::user::unlink_oauth::unlink_oauth,
|
||||||
|
crate::api::user::list_security_logs::list_security_logs,
|
||||||
|
crate::api::user::list_personal_access_tokens::list_tokens,
|
||||||
|
crate::api::user::revoke_personal_access_token::revoke_token,
|
||||||
|
// Issues - Core
|
||||||
|
crate::api::issue::list::list,
|
||||||
|
crate::api::issue::get::get,
|
||||||
|
crate::api::issue::create::create,
|
||||||
|
crate::api::issue::update::update,
|
||||||
|
crate::api::issue::close::close,
|
||||||
|
crate::api::issue::reopen::reopen,
|
||||||
|
crate::api::issue::delete::delete,
|
||||||
|
crate::api::issue::lock::lock,
|
||||||
|
crate::api::issue::transfer::transfer,
|
||||||
|
// Issues - Comments
|
||||||
|
crate::api::issue::list_comments::list_comments,
|
||||||
|
crate::api::issue::create_comment::create_comment,
|
||||||
|
crate::api::issue::update_comment::update_comment,
|
||||||
|
crate::api::issue::delete_comment::delete_comment,
|
||||||
|
// Issues - Labels (repo-level)
|
||||||
|
crate::api::issue::list_labels::list_labels,
|
||||||
|
crate::api::issue::create_label::create_label,
|
||||||
|
crate::api::issue::update_label::update_label,
|
||||||
|
crate::api::issue::delete_label::delete_label,
|
||||||
|
// Issues - Label relations (issue-level)
|
||||||
|
crate::api::issue::list_issue_labels::list_issue_labels,
|
||||||
|
crate::api::issue::assign_label::assign_label,
|
||||||
|
crate::api::issue::unassign_label::unassign_label,
|
||||||
|
// Issues - Milestones (repo-level)
|
||||||
|
crate::api::issue::list_milestones::list_milestones,
|
||||||
|
crate::api::issue::create_milestone::create_milestone,
|
||||||
|
crate::api::issue::update_milestone::update_milestone,
|
||||||
|
crate::api::issue::delete_milestone::delete_milestone,
|
||||||
|
// Issues - Assignees
|
||||||
|
crate::api::issue::list_assignees::list_assignees,
|
||||||
|
crate::api::issue::assign_issue::assign_issue,
|
||||||
|
crate::api::issue::unassign_issue::unassign_issue,
|
||||||
|
// Issues - Events
|
||||||
|
crate::api::issue::list_events::list_events,
|
||||||
|
// Issues - Reactions
|
||||||
|
crate::api::issue::reactions::list_reactions,
|
||||||
|
crate::api::issue::reactions::add_reaction,
|
||||||
|
crate::api::issue::reactions::remove_reaction,
|
||||||
|
// Issues - Subscribers
|
||||||
|
crate::api::issue::subscribers::list_subscribers,
|
||||||
|
crate::api::issue::subscribers::subscribe,
|
||||||
|
crate::api::issue::subscribers::unsubscribe,
|
||||||
|
crate::api::issue::subscribers::mute,
|
||||||
|
// Issues - Templates (repo-level)
|
||||||
|
crate::api::issue::templates::list_templates,
|
||||||
|
crate::api::issue::templates::create_template,
|
||||||
|
crate::api::issue::templates::update_template,
|
||||||
|
crate::api::issue::templates::delete_template,
|
||||||
|
// Issues - Repo relations
|
||||||
|
crate::api::issue::repo_relations::list_repo_relations,
|
||||||
|
crate::api::issue::repo_relations::link_repo,
|
||||||
|
crate::api::issue::repo_relations::unlink_repo,
|
||||||
|
// Issues - PR relations
|
||||||
|
crate::api::issue::pr_relations::list_pr_relations,
|
||||||
|
crate::api::issue::pr_relations::link_pr,
|
||||||
|
crate::api::issue::pr_relations::unlink_pr,
|
||||||
// Workspaces
|
// Workspaces
|
||||||
crate::api::workspace::list::handle,
|
crate::api::workspace::list::handle,
|
||||||
crate::api::workspace::get::handle,
|
crate::api::workspace::get::handle,
|
||||||
@@ -225,6 +340,101 @@ use crate::service::workspace::webhooks::{CreateWebhookParams, UpdateWebhookPara
|
|||||||
Disable2FAParams,
|
Disable2FAParams,
|
||||||
Regenerate2FABackupCodesRequest,
|
Regenerate2FABackupCodesRequest,
|
||||||
Regenerate2FABackupCodesResponse,
|
Regenerate2FABackupCodesResponse,
|
||||||
|
// User
|
||||||
|
ApiResponse<User>,
|
||||||
|
ApiResponse<UserAvatarResponse>,
|
||||||
|
ApiResponse<String>,
|
||||||
|
User,
|
||||||
|
UpdateUserAccountParams,
|
||||||
|
UploadUserAvatarParams,
|
||||||
|
UserAvatarResponse,
|
||||||
|
ApiResponse<UserAppearance>,
|
||||||
|
UserAppearance,
|
||||||
|
UpdateUserAppearanceParams,
|
||||||
|
ApiResponse<UserProfile>,
|
||||||
|
UserProfile,
|
||||||
|
UpdateUserProfileParams,
|
||||||
|
ApiResponse<UserNotifySetting>,
|
||||||
|
UserNotifySetting,
|
||||||
|
UpdateUserNotifySettingParams,
|
||||||
|
ApiResponse<UserSshKey>,
|
||||||
|
ApiResponse<Vec<UserSshKey>>,
|
||||||
|
UserSshKey,
|
||||||
|
AddSshKeyParams,
|
||||||
|
ApiResponse<UserGpgKey>,
|
||||||
|
ApiResponse<Vec<UserGpgKey>>,
|
||||||
|
UserGpgKey,
|
||||||
|
AddGpgKeyParams,
|
||||||
|
ApiResponse<UserSessionInfo>,
|
||||||
|
ApiResponse<Vec<UserSessionInfo>>,
|
||||||
|
UserSessionInfo,
|
||||||
|
ApiResponse<UserDevice>,
|
||||||
|
ApiResponse<Vec<UserDevice>>,
|
||||||
|
UserDevice,
|
||||||
|
ApiResponse<UserOAuthInfo>,
|
||||||
|
ApiResponse<Vec<UserOAuthInfo>>,
|
||||||
|
UserOAuthInfo,
|
||||||
|
ApiResponse<UserSecurityLog>,
|
||||||
|
ApiResponse<Vec<UserSecurityLog>>,
|
||||||
|
UserSecurityLog,
|
||||||
|
ApiResponse<UserPersonalAccessTokenInfo>,
|
||||||
|
ApiResponse<Vec<UserPersonalAccessTokenInfo>>,
|
||||||
|
UserPersonalAccessTokenInfo,
|
||||||
|
// Issues
|
||||||
|
ApiResponse<Issue>,
|
||||||
|
ApiResponse<Vec<Issue>>,
|
||||||
|
Issue,
|
||||||
|
CreateIssueParams,
|
||||||
|
IssueListFilters,
|
||||||
|
UpdateIssueParams,
|
||||||
|
LockIssueParams,
|
||||||
|
TransferIssueParams,
|
||||||
|
ApiResponse<IssueComment>,
|
||||||
|
ApiResponse<Vec<IssueComment>>,
|
||||||
|
IssueComment,
|
||||||
|
CreateCommentParams,
|
||||||
|
UpdateCommentParams,
|
||||||
|
ApiResponse<IssueLabel>,
|
||||||
|
ApiResponse<Vec<IssueLabel>>,
|
||||||
|
IssueLabel,
|
||||||
|
CreateLabelParams,
|
||||||
|
UpdateLabelParams,
|
||||||
|
ApiResponse<IssueLabelRelation>,
|
||||||
|
ApiResponse<Vec<IssueLabelRelation>>,
|
||||||
|
IssueLabelRelation,
|
||||||
|
ApiResponse<IssueMilestone>,
|
||||||
|
ApiResponse<Vec<IssueMilestone>>,
|
||||||
|
IssueMilestone,
|
||||||
|
CreateMilestoneParams,
|
||||||
|
UpdateMilestoneParams,
|
||||||
|
ApiResponse<IssueAssignee>,
|
||||||
|
ApiResponse<Vec<IssueAssignee>>,
|
||||||
|
IssueAssignee,
|
||||||
|
ApiResponse<IssueEvent>,
|
||||||
|
ApiResponse<Vec<IssueEvent>>,
|
||||||
|
IssueEvent,
|
||||||
|
ApiResponse<IssueReaction>,
|
||||||
|
ApiResponse<Vec<IssueReaction>>,
|
||||||
|
IssueReaction,
|
||||||
|
CreateIssueReactionParams,
|
||||||
|
ApiResponse<IssueSubscriber>,
|
||||||
|
ApiResponse<Vec<IssueSubscriber>>,
|
||||||
|
IssueSubscriber,
|
||||||
|
MuteIssueParams,
|
||||||
|
ApiResponse<IssueTemplate>,
|
||||||
|
ApiResponse<Vec<IssueTemplate>>,
|
||||||
|
IssueTemplate,
|
||||||
|
CreateTemplateParams,
|
||||||
|
UpdateTemplateParams,
|
||||||
|
ApiResponse<IssueRepoRelation>,
|
||||||
|
ApiResponse<Vec<IssueRepoRelation>>,
|
||||||
|
IssueRepoRelation,
|
||||||
|
LinkRepoParams,
|
||||||
|
ApiResponse<IssuePrRelation>,
|
||||||
|
ApiResponse<Vec<IssuePrRelation>>,
|
||||||
|
IssuePrRelation,
|
||||||
|
LinkPrParams,
|
||||||
|
// Workspaces
|
||||||
ApiResponse<Workspace>,
|
ApiResponse<Workspace>,
|
||||||
ApiResponse<Vec<Workspace>>,
|
ApiResponse<Vec<Workspace>>,
|
||||||
ApiResponse<WorkspaceMember>,
|
ApiResponse<WorkspaceMember>,
|
||||||
@@ -307,7 +517,6 @@ use crate::service::workspace::webhooks::{CreateWebhookParams, UpdateWebhookPara
|
|||||||
ApiResponse<RepoCommitComment>,
|
ApiResponse<RepoCommitComment>,
|
||||||
ApiResponse<Vec<RepoCommitComment>>,
|
ApiResponse<Vec<RepoCommitComment>>,
|
||||||
ApiResponse<RepoStats>,
|
ApiResponse<RepoStats>,
|
||||||
ApiResponse<String>,
|
|
||||||
Repo,
|
Repo,
|
||||||
CreateRepoParams,
|
CreateRepoParams,
|
||||||
UpdateRepoParams,
|
UpdateRepoParams,
|
||||||
@@ -334,8 +543,8 @@ use crate::service::workspace::webhooks::{CreateWebhookParams, UpdateWebhookPara
|
|||||||
RepoDeployKey,
|
RepoDeployKey,
|
||||||
AddDeployKeyParams,
|
AddDeployKeyParams,
|
||||||
RepoWebhook,
|
RepoWebhook,
|
||||||
CreateWebhookParams,
|
RepoCreateWebhookParams,
|
||||||
UpdateWebhookParams,
|
RepoUpdateWebhookParams,
|
||||||
BranchProtectionRule,
|
BranchProtectionRule,
|
||||||
CreateProtectionRuleParams,
|
CreateProtectionRuleParams,
|
||||||
UpdateProtectionRuleParams,
|
UpdateProtectionRuleParams,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoInvitation;
|
use crate::models::repos::RepoInvitation;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -18,12 +18,12 @@ pub struct AcceptInvitationParams {
|
|||||||
///
|
///
|
||||||
/// Accepts a pending repository invitation using the token received via email.
|
/// Accepts a pending repository invitation using the token received via email.
|
||||||
/// Requires authentication and a verified email address matching the invitation.
|
/// Requires authentication and a verified email address matching the invitation.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - User is added as a repository member with the invited role
|
/// - User is added as a repository member with the invited role
|
||||||
/// - User is added to the workspace if not already a member
|
/// - User is added to the workspace if not already a member
|
||||||
/// - Invitation is marked as accepted
|
/// - Invitation is marked as accepted
|
||||||
///
|
///
|
||||||
/// Returns the accepted invitation with full metadata.
|
/// Returns the accepted invitation with full metadata.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoDeployKey;
|
use crate::models::repos::RepoDeployKey;
|
||||||
use crate::service::repo::deploy_keys::AddDeployKeyParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::deploy_keys::AddDeployKeyParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,17 +21,17 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Adds an SSH public key for automated deployments and CI/CD access to the repository.
|
/// Adds an SSH public key for automated deployments and CI/CD access to the repository.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - title: Human-readable name for the deploy key (1-100 characters)
|
/// - title: Human-readable name for the deploy key (1-100 characters)
|
||||||
/// - key: SSH public key in OpenSSH format (e.g., "ssh-rsa AAAA...")
|
/// - key: SSH public key in OpenSSH format (e.g., "ssh-rsa AAAA...")
|
||||||
/// - read_only: Whether the key has read-only access (default: true)
|
/// - read_only: Whether the key has read-only access (default: true)
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Deploy key is added to the repository
|
/// - Deploy key is added to the repository
|
||||||
/// - Key can be used for Git operations (clone, fetch, push if not read-only)
|
/// - Key can be used for Git operations (clone, fetch, push if not read-only)
|
||||||
/// - Key fingerprint is calculated and stored
|
/// - Key fingerprint is calculated and stored
|
||||||
///
|
///
|
||||||
/// Returns the created deploy key with metadata including fingerprint.
|
/// Returns the created deploy key with metadata including fingerprint.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -65,7 +65,12 @@ pub async fn add_deploy_key(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let key = service
|
let key = service
|
||||||
.repo
|
.repo
|
||||||
.repo_add_deploy_key(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_add_deploy_key(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(key)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(key)))
|
||||||
|
|||||||
+11
-6
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoMember;
|
use crate::models::repos::RepoMember;
|
||||||
use crate::service::repo::members::AddRepoMemberParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::members::AddRepoMemberParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Grants a user access to the repository with a specific role.
|
/// Grants a user access to the repository with a specific role.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Requirements:
|
/// Requirements:
|
||||||
/// - User must exist in the system
|
/// - User must exist in the system
|
||||||
/// - User must be a member of the workspace
|
/// - User must be a member of the workspace
|
||||||
/// - Role must be one of: "read", "write", "admin" (cannot assign "owner")
|
/// - Role must be one of: "read", "write", "admin" (cannot assign "owner")
|
||||||
///
|
///
|
||||||
/// Returns the created member record with user information and role.
|
/// Returns the created member record with user information and role.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -60,7 +60,12 @@ pub async fn add_member(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let member = service
|
let member = service
|
||||||
.repo
|
.repo
|
||||||
.repo_add_member(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_add_member(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(member)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(member)))
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,13 +19,13 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Marks a repository as archived, making it read-only. All write operations (push, create issues, etc.) are disabled.
|
/// Marks a repository as archived, making it read-only. All write operations (push, create issues, etc.) are disabled.
|
||||||
/// Requires Owner role in the repository.
|
/// Requires Owner role in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Repository status changes to "archived"
|
/// - Repository status changes to "archived"
|
||||||
/// - All write operations are blocked
|
/// - All write operations are blocked
|
||||||
/// - Repository remains visible based on its visibility setting
|
/// - Repository remains visible based on its visibility setting
|
||||||
/// - Can be unarchived later by repository owners
|
/// - Can be unarchived later by repository owners
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::repo::protection::BranchMergeCheck;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::protection::BranchMergeCheck;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
|
|||||||
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::repo::core::CreateRepoParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::core::CreateRepoParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -18,17 +18,17 @@ pub struct PathParams {
|
|||||||
/// Create a new repository
|
/// Create a new repository
|
||||||
///
|
///
|
||||||
/// Creates a new Git repository within the specified workspace. The authenticated user becomes the repository owner.
|
/// Creates a new Git repository within the specified workspace. The authenticated user becomes the repository owner.
|
||||||
///
|
///
|
||||||
/// Requirements:
|
/// Requirements:
|
||||||
/// - User must have at least Member role in the workspace
|
/// - User must have at least Member role in the workspace
|
||||||
/// - Repository name must be unique within the workspace
|
/// - Repository name must be unique within the workspace
|
||||||
/// - Name must be 1-100 characters, alphanumeric, hyphens, underscores, and dots allowed
|
/// - Name must be 1-100 characters, alphanumeric, hyphens, underscores, and dots allowed
|
||||||
///
|
///
|
||||||
/// Optional parameters:
|
/// Optional parameters:
|
||||||
/// - description: Repository description (max 500 characters)
|
/// - description: Repository description (max 500 characters)
|
||||||
/// - visibility: "public", "private", or "internal" (defaults to workspace setting)
|
/// - visibility: "public", "private", or "internal" (defaults to workspace setting)
|
||||||
/// - default_branch: Default branch name (defaults to "main")
|
/// - default_branch: Default branch name (defaults to "main")
|
||||||
///
|
///
|
||||||
/// Returns the created repository with full metadata.
|
/// Returns the created repository with full metadata.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoBranch;
|
use crate::models::repos::RepoBranch;
|
||||||
use crate::service::repo::branches::CreateBranchParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::branches::CreateBranchParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,11 +21,11 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new branch in the repository based on an existing commit or branch.
|
/// Creates a new branch in the repository based on an existing commit or branch.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - name: Branch name (1-100 characters, alphanumeric, hyphens, underscores, dots, slashes allowed)
|
/// - name: Branch name (1-100 characters, alphanumeric, hyphens, underscores, dots, slashes allowed)
|
||||||
/// - from: Source branch name or commit SHA to branch from (defaults to default branch)
|
/// - from: Source branch name or commit SHA to branch from (defaults to default branch)
|
||||||
///
|
///
|
||||||
/// Returns the created branch with metadata including the initial commit SHA.
|
/// Returns the created branch with metadata including the initial commit SHA.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -59,7 +59,12 @@ pub async fn create_branch(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let branch = service
|
let branch = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_branch(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_branch(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(branch)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(branch)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoCommitComment;
|
use crate::models::repos::RepoCommitComment;
|
||||||
use crate::service::repo::commit_status::CreateCommitCommentParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::commit_status::CreateCommitCommentParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,18 +21,18 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new comment on a specific commit. Comments can be general or inline (attached to a specific file and line).
|
/// Creates a new comment on a specific commit. Comments can be general or inline (attached to a specific file and line).
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - commit_sha: Commit SHA to comment on (must exist in repository)
|
/// - commit_sha: Commit SHA to comment on (must exist in repository)
|
||||||
/// - body: Comment body in markdown format (1-10000 characters)
|
/// - body: Comment body in markdown format (1-10000 characters)
|
||||||
/// - path: File path for inline comments (optional)
|
/// - path: File path for inline comments (optional)
|
||||||
/// - line: Line number for inline comments (optional, requires path)
|
/// - line: Line number for inline comments (optional, requires path)
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Comment is attached to the commit
|
/// - Comment is attached to the commit
|
||||||
/// - Comment author receives notifications for replies
|
/// - Comment author receives notifications for replies
|
||||||
/// - Inline comments appear in code review interfaces
|
/// - Inline comments appear in code review interfaces
|
||||||
///
|
///
|
||||||
/// Returns the created comment with metadata including ID and timestamps.
|
/// Returns the created comment with metadata including ID and timestamps.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -65,7 +65,12 @@ pub async fn create_commit_comment(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let comment = service
|
let comment = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_commit_comment(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_commit_comment(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(comment)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(comment)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoCommitStatus;
|
use crate::models::repos::RepoCommitStatus;
|
||||||
use crate::service::repo::commit_status::CreateCommitStatusParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::commit_status::CreateCommitStatusParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,19 +21,19 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new status check for a specific commit, typically used by CI/CD systems.
|
/// Creates a new status check for a specific commit, typically used by CI/CD systems.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - commit_sha: Commit SHA to attach the status to (must exist in repository)
|
/// - commit_sha: Commit SHA to attach the status to (must exist in repository)
|
||||||
/// - state: Status state ("pending", "success", "failure", "error")
|
/// - state: Status state ("pending", "success", "failure", "error")
|
||||||
/// - context: Status context name (e.g., "ci/build", "ci/test") - must be unique per commit
|
/// - context: Status context name (e.g., "ci/build", "ci/test") - must be unique per commit
|
||||||
/// - description: Human-readable description of the status (optional, max 500 characters)
|
/// - description: Human-readable description of the status (optional, max 500 characters)
|
||||||
/// - target_url: URL with detailed information about the status (optional)
|
/// - target_url: URL with detailed information about the status (optional)
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Status is attached to the commit
|
/// - Status is attached to the commit
|
||||||
/// - Can be used by branch protection rules to enforce status checks
|
/// - Can be used by branch protection rules to enforce status checks
|
||||||
/// - Multiple statuses can exist for the same commit with different contexts
|
/// - Multiple statuses can exist for the same commit with different contexts
|
||||||
///
|
///
|
||||||
/// Returns the created status with metadata including ID and timestamps.
|
/// Returns the created status with metadata including ID and timestamps.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -67,7 +67,12 @@ pub async fn create_commit_status(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let status = service
|
let status = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_commit_status(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_commit_status(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(status)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(status)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoInvitation;
|
use crate::models::repos::RepoInvitation;
|
||||||
use crate::service::repo::invitations::CreateRepoInvitationParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::invitations::CreateRepoInvitationParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,16 +21,16 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Sends an invitation email to a user to join the repository with a specific role.
|
/// Sends an invitation email to a user to join the repository with a specific role.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - email: Email address of the invitee (must be a valid email)
|
/// - email: Email address of the invitee (must be a valid email)
|
||||||
/// - role: Role to assign when invitation is accepted ("read", "write", "admin")
|
/// - role: Role to assign when invitation is accepted ("read", "write", "admin")
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Invitation email is sent to the invitee
|
/// - Invitation email is sent to the invitee
|
||||||
/// - Invitation expires after 7 days
|
/// - Invitation expires after 7 days
|
||||||
/// - Invitee must have a verified email to accept
|
/// - Invitee must have a verified email to accept
|
||||||
///
|
///
|
||||||
/// Returns the created invitation with metadata including expiration date.
|
/// Returns the created invitation with metadata including expiration date.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -64,7 +64,12 @@ pub async fn create_invitation(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let invitation = service
|
let invitation = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_invitation(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_invitation(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(invitation)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(invitation)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::BranchProtectionRule;
|
use crate::models::repos::BranchProtectionRule;
|
||||||
use crate::service::repo::protection::CreateProtectionRuleParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::protection::CreateProtectionRuleParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,7 +21,7 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new branch protection rule that enforces policies on matching branches.
|
/// Creates a new branch protection rule that enforces policies on matching branches.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - pattern: Branch name pattern (supports wildcards like "feature/*", "release/**")
|
/// - pattern: Branch name pattern (supports wildcards like "feature/*", "release/**")
|
||||||
/// - required_approvals: Number of required approvals before merging (0-10)
|
/// - required_approvals: Number of required approvals before merging (0-10)
|
||||||
@@ -30,7 +30,7 @@ pub struct PathParams {
|
|||||||
/// - restrict_pushes: Restrict who can push to matching branches
|
/// - restrict_pushes: Restrict who can push to matching branches
|
||||||
/// - allow_force_pushes: Allow force pushes (only if restrict_pushes is false)
|
/// - allow_force_pushes: Allow force pushes (only if restrict_pushes is false)
|
||||||
/// - allow_deletions: Allow branch deletion (only if restrict_pushes is false)
|
/// - allow_deletions: Allow branch deletion (only if restrict_pushes is false)
|
||||||
///
|
///
|
||||||
/// Returns the created protection rule with full configuration.
|
/// Returns the created protection rule with full configuration.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -64,7 +64,12 @@ pub async fn create_protection_rule(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let rule = service
|
let rule = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_protection_rule(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_protection_rule(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(rule)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(rule)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoRelease;
|
use crate::models::repos::RepoRelease;
|
||||||
use crate::service::repo::releases::CreateReleaseParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::releases::CreateReleaseParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,7 +21,7 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new release in the repository, optionally creating a tag if it doesn't exist.
|
/// Creates a new release in the repository, optionally creating a tag if it doesn't exist.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - tag_name: Tag name for the release (will be created if it doesn't exist)
|
/// - tag_name: Tag name for the release (will be created if it doesn't exist)
|
||||||
/// - name: Release name/title (required)
|
/// - name: Release name/title (required)
|
||||||
@@ -29,7 +29,7 @@ pub struct PathParams {
|
|||||||
/// - draft: Whether this is a draft release (default: false)
|
/// - draft: Whether this is a draft release (default: false)
|
||||||
/// - prerelease: Whether this is a prerelease (default: false)
|
/// - prerelease: Whether this is a prerelease (default: false)
|
||||||
/// - target_commitish: Commit SHA or branch name to tag (defaults to default branch)
|
/// - target_commitish: Commit SHA or branch name to tag (defaults to default branch)
|
||||||
///
|
///
|
||||||
/// Returns the created release with metadata including download URLs for assets.
|
/// Returns the created release with metadata including download URLs for assets.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -63,7 +63,12 @@ pub async fn create_release(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let release = service
|
let release = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_release(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_release(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(release)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(release)))
|
||||||
|
|||||||
+11
-6
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoTag;
|
use crate::models::repos::RepoTag;
|
||||||
use crate::service::repo::tags::CreateTagParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::tags::CreateTagParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new tag in the repository pointing to a specific commit or branch.
|
/// Creates a new tag in the repository pointing to a specific commit or branch.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - name: Tag name (1-100 characters, typically follows semantic versioning like v1.0.0)
|
/// - name: Tag name (1-100 characters, typically follows semantic versioning like v1.0.0)
|
||||||
/// - target: Commit SHA or branch name to tag (defaults to HEAD of default branch)
|
/// - target: Commit SHA or branch name to tag (defaults to HEAD of default branch)
|
||||||
/// - message: Optional tag message for annotated tags
|
/// - message: Optional tag message for annotated tags
|
||||||
///
|
///
|
||||||
/// Returns the created tag with metadata including the commit SHA.
|
/// Returns the created tag with metadata including the commit SHA.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -60,7 +60,12 @@ pub async fn create_tag(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let tag = service
|
let tag = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_tag(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_tag(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(tag)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(tag)))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoWebhook;
|
use crate::models::repos::RepoWebhook;
|
||||||
use crate::service::repo::webhooks::CreateWebhookParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::webhooks::CreateWebhookParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,17 +21,17 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Creates a new webhook that receives HTTP POST notifications for repository events.
|
/// Creates a new webhook that receives HTTP POST notifications for repository events.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// - url: Webhook endpoint URL (must be HTTPS in production)
|
/// - url: Webhook endpoint URL (must be HTTPS in production)
|
||||||
/// - events: List of events to subscribe to (e.g., "push", "pull_request", "issue")
|
/// - events: List of events to subscribe to (e.g., "push", "pull_request", "issue")
|
||||||
/// - secret: Optional secret for webhook signature verification
|
/// - secret: Optional secret for webhook signature verification
|
||||||
/// - active: Whether the webhook is active (default: true)
|
/// - active: Whether the webhook is active (default: true)
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Webhook is created and starts receiving events
|
/// - Webhook is created and starts receiving events
|
||||||
/// - Webhook deliveries are logged and can be retried on failure
|
/// - Webhook deliveries are logged and can be retried on failure
|
||||||
///
|
///
|
||||||
/// Returns the created webhook with metadata including ID and configuration.
|
/// Returns the created webhook with metadata including ID and configuration.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -64,7 +64,12 @@ pub async fn create_webhook(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let webhook = service
|
let webhook = service
|
||||||
.repo
|
.repo
|
||||||
.repo_create_webhook(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_create_webhook(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(webhook)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(webhook)))
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -23,9 +23,9 @@ pub struct PathParams {
|
|||||||
/// - Issues, pull requests, and comments
|
/// - Issues, pull requests, and comments
|
||||||
/// - Webhooks, deploy keys, and protection rules
|
/// - Webhooks, deploy keys, and protection rules
|
||||||
/// - Stars, watches, and forks
|
/// - Stars, watches, and forks
|
||||||
///
|
///
|
||||||
/// Requires Owner role in the repository. This action is irreversible.
|
/// Requires Owner role in the repository. This action is irreversible.
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Permanently deletes a branch from the repository. The default branch cannot be deleted.
|
/// Permanently deletes a branch from the repository. The default branch cannot be deleted.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Branch is permanently removed from the repository
|
/// - Branch is permanently removed from the repository
|
||||||
/// - All commits exclusive to this branch remain accessible via their SHA
|
/// - All commits exclusive to this branch remain accessible via their SHA
|
||||||
/// - Open pull requests targeting this branch will be closed
|
/// - Open pull requests targeting this branch will be closed
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -53,7 +53,12 @@ pub async fn delete_branch(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_delete_branch(&session, &path.workspace_name, &path.repo_name, path.branch_id)
|
.repo_delete_branch(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.branch_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Branch deleted successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Branch deleted successfully".to_string())))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Removes an SSH deploy key from the repository, revoking its access.
|
/// Removes an SSH deploy key from the repository, revoking its access.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Deploy key is permanently removed from the repository
|
/// - Deploy key is permanently removed from the repository
|
||||||
/// - Key can no longer be used for Git operations
|
/// - Key can no longer be used for Git operations
|
||||||
/// - Automated systems using this key will lose access
|
/// - Automated systems using this key will lose access
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -55,5 +55,7 @@ pub async fn delete_deploy_key(
|
|||||||
.repo_delete_deploy_key(&session, &path.workspace_name, &path.repo_name, path.key_id)
|
.repo_delete_deploy_key(&session, &path.workspace_name, &path.repo_name, path.key_id)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Deploy key deleted successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Deploy key deleted successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Permanently removes a branch protection rule from the repository.
|
/// Permanently removes a branch protection rule from the repository.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Protection rule is permanently removed
|
/// - Protection rule is permanently removed
|
||||||
/// - Branches matching the pattern are no longer protected by this rule
|
/// - Branches matching the pattern are no longer protected by this rule
|
||||||
/// - Pushes and merges to matching branches are no longer restricted
|
/// - Pushes and merges to matching branches are no longer restricted
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -52,8 +52,15 @@ pub async fn delete_protection_rule(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_delete_protection_rule(&session, &path.workspace_name, &path.repo_name, path.rule_id)
|
.repo_delete_protection_rule(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.rule_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Protection rule deleted successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Protection rule deleted successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,13 +21,13 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Permanently deletes a release from the repository. The associated tag and commits are not deleted.
|
/// Permanently deletes a release from the repository. The associated tag and commits are not deleted.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Release metadata is permanently removed
|
/// - Release metadata is permanently removed
|
||||||
/// - Release assets are deleted
|
/// - Release assets are deleted
|
||||||
/// - The associated tag remains in the repository
|
/// - The associated tag remains in the repository
|
||||||
/// - The tagged commits remain in the repository history
|
/// - The tagged commits remain in the repository history
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -53,7 +53,12 @@ pub async fn delete_release(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_delete_release(&session, &path.workspace_name, &path.repo_name, path.release_id)
|
.repo_delete_release(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.release_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Release deleted successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Release deleted successfully".to_string())))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Permanently deletes a tag from the repository. The tagged commit remains accessible via its SHA.
|
/// Permanently deletes a tag from the repository. The tagged commit remains accessible via its SHA.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Tag is permanently removed from the repository
|
/// - Tag is permanently removed from the repository
|
||||||
/// - The tagged commit remains in the repository history
|
/// - The tagged commit remains in the repository history
|
||||||
/// - Releases associated with this tag are not automatically deleted
|
/// - Releases associated with this tag are not automatically deleted
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Permanently removes a webhook from the repository, stopping all event notifications.
|
/// Permanently removes a webhook from the repository, stopping all event notifications.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Webhook is permanently removed from the repository
|
/// - Webhook is permanently removed from the repository
|
||||||
/// - Webhook stops receiving event notifications immediately
|
/// - Webhook stops receiving event notifications immediately
|
||||||
/// - Webhook delivery history is deleted
|
/// - Webhook delivery history is deleted
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -52,7 +52,12 @@ pub async fn delete_webhook(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_delete_webhook(&session, &path.workspace_name, &path.repo_name, path.webhook_id)
|
.repo_delete_webhook(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.webhook_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Webhook deleted successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Webhook deleted successfully".to_string())))
|
||||||
|
|||||||
+10
-5
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -22,13 +22,13 @@ use crate::service::repo::fork::ForkRepoParams;
|
|||||||
///
|
///
|
||||||
/// Creates a copy of the repository in the specified workspace or the current user's workspace.
|
/// Creates a copy of the repository in the specified workspace or the current user's workspace.
|
||||||
/// Requires read access to the source repository and write access to the target workspace.
|
/// Requires read access to the source repository and write access to the target workspace.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Creates a new repository with all branches, tags, and commit history
|
/// - Creates a new repository with all branches, tags, and commit history
|
||||||
/// - Establishes a parent-child relationship between source and fork
|
/// - Establishes a parent-child relationship between source and fork
|
||||||
/// - Fork is initially set to private visibility
|
/// - Fork is initially set to private visibility
|
||||||
/// - Current user becomes the owner of the fork
|
/// - Current user becomes the owner of the fork
|
||||||
///
|
///
|
||||||
/// Returns the created fork repository with full metadata.
|
/// Returns the created fork repository with full metadata.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -62,7 +62,12 @@ pub async fn fork_repo(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let repo = service
|
let repo = service
|
||||||
.repo
|
.repo
|
||||||
.repo_fork(&session, &path.workspace_name, &path.repo_name, params.into_inner())
|
.repo_fork(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
params.into_inner(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Created().json(ApiResponse::new(repo)))
|
Ok(HttpResponse::Created().json(ApiResponse::new(repo)))
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::BranchProtectionRule;
|
use crate::models::repos::BranchProtectionRule;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -22,7 +22,7 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Returns detailed information about a specific branch protection rule.
|
/// Returns detailed information about a specific branch protection rule.
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
///
|
///
|
||||||
/// Returns the complete protection rule with all configuration details including:
|
/// Returns the complete protection rule with all configuration details including:
|
||||||
/// - Branch name pattern
|
/// - Branch name pattern
|
||||||
/// - Required approvals and status checks
|
/// - Required approvals and status checks
|
||||||
@@ -52,7 +52,12 @@ pub async fn get_protection_rule(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
let rule = service
|
let rule = service
|
||||||
.repo
|
.repo
|
||||||
.repo_get_protection_rule(&session, &path.workspace_name, &path.repo_name, path.rule_id)
|
.repo_get_protection_rule(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.rule_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new(rule)))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(rule)))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoStats;
|
use crate::models::repos::RepoStats;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -27,7 +27,7 @@ pub struct PathParams {
|
|||||||
/// - Open issues and pull requests count
|
/// - Open issues and pull requests count
|
||||||
/// - Storage size and bandwidth usage
|
/// - Storage size and bandwidth usage
|
||||||
/// - Last push timestamp
|
/// - Last push timestamp
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,14 +19,14 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Removes the current user's access to the repository.
|
/// Removes the current user's access to the repository.
|
||||||
/// Requires the user to be a member of the repository.
|
/// Requires the user to be a member of the repository.
|
||||||
///
|
///
|
||||||
/// Restrictions:
|
/// Restrictions:
|
||||||
/// - Repository owner cannot leave (use transfer_owner instead)
|
/// - Repository owner cannot leave (use transfer_owner instead)
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - User loses all access to the repository
|
/// - User loses all access to the repository
|
||||||
/// - User is removed from all repository activities
|
/// - User is removed from all repository activities
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoBranch;
|
use crate::models::repos::RepoBranch;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -32,7 +32,7 @@ pub struct QueryParams {
|
|||||||
/// - Protected status
|
/// - Protected status
|
||||||
/// - Default branch flag
|
/// - Default branch flag
|
||||||
/// - Last push information
|
/// - Last push information
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoCommitComment;
|
use crate::models::repos::RepoCommitComment;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -35,7 +35,7 @@ pub struct QueryParams {
|
|||||||
/// - File path and line number (for inline comments)
|
/// - File path and line number (for inline comments)
|
||||||
/// - Resolved status
|
/// - Resolved status
|
||||||
/// - Creation and update timestamps
|
/// - Creation and update timestamps
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoCommitStatus;
|
use crate::models::repos::RepoCommitStatus;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -34,7 +34,7 @@ pub struct QueryParams {
|
|||||||
/// - Context name (e.g., "ci/build", "ci/test")
|
/// - Context name (e.g., "ci/build", "ci/test")
|
||||||
/// - Description and target URL
|
/// - Description and target URL
|
||||||
/// - Creator information
|
/// - Creator information
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoDeployKey;
|
use crate::models::repos::RepoDeployKey;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -32,7 +32,7 @@ pub struct QueryParams {
|
|||||||
/// - Read-only status
|
/// - Read-only status
|
||||||
/// - Creator information
|
/// - Creator information
|
||||||
/// - Creation date and last used date
|
/// - Creation date and last used date
|
||||||
///
|
///
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoFork;
|
use crate::models::repos::RepoFork;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -31,7 +31,7 @@ pub struct QueryParams {
|
|||||||
/// - Fork repository information
|
/// - Fork repository information
|
||||||
/// - Fork owner and workspace
|
/// - Fork owner and workspace
|
||||||
/// - Fork creation date
|
/// - Fork creation date
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoInvitation;
|
use crate::models::repos::RepoInvitation;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -33,7 +33,7 @@ pub struct QueryParams {
|
|||||||
/// - Inviter information
|
/// - Inviter information
|
||||||
/// - Expiration date
|
/// - Expiration date
|
||||||
/// - Creation date
|
/// - Creation date
|
||||||
///
|
///
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoMember;
|
use crate::models::repos::RepoMember;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -31,7 +31,7 @@ pub struct QueryParams {
|
|||||||
/// - User information (ID, username, display name)
|
/// - User information (ID, username, display name)
|
||||||
/// - Role (owner, admin, write, read)
|
/// - Role (owner, admin, write, read)
|
||||||
/// - Join date and last activity
|
/// - Join date and last activity
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::BranchProtectionRule;
|
use crate::models::repos::BranchProtectionRule;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -33,7 +33,7 @@ pub struct QueryParams {
|
|||||||
/// - Required status checks
|
/// - Required status checks
|
||||||
/// - Restrictions on pushes and deletions
|
/// - Restrictions on pushes and deletions
|
||||||
/// - Creator information
|
/// - Creator information
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoRelease;
|
use crate::models::repos::RepoRelease;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -33,7 +33,7 @@ pub struct QueryParams {
|
|||||||
/// - Author and creation date
|
/// - Author and creation date
|
||||||
/// - Draft and prerelease status
|
/// - Draft and prerelease status
|
||||||
/// - Asset download URLs
|
/// - Asset download URLs
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoStar;
|
use crate::models::repos::RepoStar;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -30,7 +30,7 @@ pub struct QueryParams {
|
|||||||
/// Includes stargazer metadata such as:
|
/// Includes stargazer metadata such as:
|
||||||
/// - User information (ID, username, display name)
|
/// - User information (ID, username, display name)
|
||||||
/// - Star timestamp
|
/// - Star timestamp
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoTag;
|
use crate::models::repos::RepoTag;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -31,7 +31,7 @@ pub struct QueryParams {
|
|||||||
/// - Tag name and commit SHA
|
/// - Tag name and commit SHA
|
||||||
/// - Tagger information and timestamp
|
/// - Tagger information and timestamp
|
||||||
/// - Tag message (for annotated tags)
|
/// - Tag message (for annotated tags)
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoWatch;
|
use crate::models::repos::RepoWatch;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -31,7 +31,7 @@ pub struct QueryParams {
|
|||||||
/// - User information (ID, username, display name)
|
/// - User information (ID, username, display name)
|
||||||
/// - Watch level (participating, watching, or ignoring)
|
/// - Watch level (participating, watching, or ignoring)
|
||||||
/// - Watch timestamp
|
/// - Watch timestamp
|
||||||
///
|
///
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoWebhook;
|
use crate::models::repos::RepoWebhook;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -32,7 +32,7 @@ pub struct QueryParams {
|
|||||||
/// - Active status
|
/// - Active status
|
||||||
/// - Last delivery status and timestamp
|
/// - Last delivery status and timestamp
|
||||||
/// - Creator information
|
/// - Creator information
|
||||||
///
|
///
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::BranchProtectionRule;
|
use crate::models::repos::BranchProtectionRule;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -26,7 +26,7 @@ pub struct QueryParams {
|
|||||||
///
|
///
|
||||||
/// Checks if a branch name matches any protection rule in the repository.
|
/// Checks if a branch name matches any protection rule in the repository.
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
///
|
///
|
||||||
/// Returns the matching protection rule if found, or null if no rules match.
|
/// Returns the matching protection rule if found, or null if no rules match.
|
||||||
/// Useful for determining what protections apply to a specific branch before performing operations.
|
/// Useful for determining what protections apply to a specific branch before performing operations.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|||||||
+121
-70
@@ -1,64 +1,64 @@
|
|||||||
use actix_web::web;
|
use actix_web::web;
|
||||||
|
|
||||||
pub mod list;
|
|
||||||
pub mod get;
|
|
||||||
pub mod create;
|
|
||||||
pub mod update;
|
|
||||||
pub mod archive;
|
|
||||||
pub mod unarchive;
|
|
||||||
pub mod delete;
|
|
||||||
pub mod transfer_owner;
|
|
||||||
pub mod list_branches;
|
|
||||||
pub mod create_branch;
|
|
||||||
pub mod set_default_branch;
|
|
||||||
pub mod set_branch_protection;
|
|
||||||
pub mod delete_branch;
|
|
||||||
pub mod list_tags;
|
|
||||||
pub mod create_tag;
|
|
||||||
pub mod delete_tag;
|
|
||||||
pub mod list_releases;
|
|
||||||
pub mod create_release;
|
|
||||||
pub mod update_release;
|
|
||||||
pub mod delete_release;
|
|
||||||
pub mod list_forks;
|
|
||||||
pub mod fork_repo;
|
|
||||||
pub mod sync_fork;
|
|
||||||
pub mod star_repo;
|
|
||||||
pub mod unstar_repo;
|
|
||||||
pub mod list_stargazers;
|
|
||||||
pub mod watch_repo;
|
|
||||||
pub mod unwatch_repo;
|
|
||||||
pub mod list_watchers;
|
|
||||||
pub mod list_members;
|
|
||||||
pub mod add_member;
|
|
||||||
pub mod update_member_role;
|
|
||||||
pub mod remove_member;
|
|
||||||
pub mod leave_repo;
|
|
||||||
pub mod list_invitations;
|
|
||||||
pub mod create_invitation;
|
|
||||||
pub mod revoke_invitation;
|
|
||||||
pub mod accept_invitation;
|
pub mod accept_invitation;
|
||||||
pub mod list_deploy_keys;
|
|
||||||
pub mod add_deploy_key;
|
pub mod add_deploy_key;
|
||||||
pub mod delete_deploy_key;
|
pub mod add_member;
|
||||||
pub mod list_webhooks;
|
pub mod archive;
|
||||||
pub mod create_webhook;
|
|
||||||
pub mod update_webhook;
|
|
||||||
pub mod delete_webhook;
|
|
||||||
pub mod list_protection_rules;
|
|
||||||
pub mod get_protection_rule;
|
|
||||||
pub mod match_protection;
|
|
||||||
pub mod create_protection_rule;
|
|
||||||
pub mod update_protection_rule;
|
|
||||||
pub mod delete_protection_rule;
|
|
||||||
pub mod check_branch_merge;
|
pub mod check_branch_merge;
|
||||||
pub mod list_commit_statuses;
|
pub mod create;
|
||||||
pub mod create_commit_status;
|
pub mod create_branch;
|
||||||
pub mod list_commit_comments;
|
|
||||||
pub mod create_commit_comment;
|
pub mod create_commit_comment;
|
||||||
pub mod resolve_commit_comment;
|
pub mod create_commit_status;
|
||||||
|
pub mod create_invitation;
|
||||||
|
pub mod create_protection_rule;
|
||||||
|
pub mod create_release;
|
||||||
|
pub mod create_tag;
|
||||||
|
pub mod create_webhook;
|
||||||
|
pub mod delete;
|
||||||
|
pub mod delete_branch;
|
||||||
|
pub mod delete_deploy_key;
|
||||||
|
pub mod delete_protection_rule;
|
||||||
|
pub mod delete_release;
|
||||||
|
pub mod delete_tag;
|
||||||
|
pub mod delete_webhook;
|
||||||
|
pub mod fork_repo;
|
||||||
|
pub mod get;
|
||||||
|
pub mod get_protection_rule;
|
||||||
pub mod get_stats;
|
pub mod get_stats;
|
||||||
|
pub mod leave_repo;
|
||||||
|
pub mod list;
|
||||||
|
pub mod list_branches;
|
||||||
|
pub mod list_commit_comments;
|
||||||
|
pub mod list_commit_statuses;
|
||||||
|
pub mod list_deploy_keys;
|
||||||
|
pub mod list_forks;
|
||||||
|
pub mod list_invitations;
|
||||||
|
pub mod list_members;
|
||||||
|
pub mod list_protection_rules;
|
||||||
|
pub mod list_releases;
|
||||||
|
pub mod list_stargazers;
|
||||||
|
pub mod list_tags;
|
||||||
|
pub mod list_watchers;
|
||||||
|
pub mod list_webhooks;
|
||||||
|
pub mod match_protection;
|
||||||
pub mod refresh_stats;
|
pub mod refresh_stats;
|
||||||
|
pub mod remove_member;
|
||||||
|
pub mod resolve_commit_comment;
|
||||||
|
pub mod revoke_invitation;
|
||||||
|
pub mod set_branch_protection;
|
||||||
|
pub mod set_default_branch;
|
||||||
|
pub mod star_repo;
|
||||||
|
pub mod sync_fork;
|
||||||
|
pub mod transfer_owner;
|
||||||
|
pub mod unarchive;
|
||||||
|
pub mod unstar_repo;
|
||||||
|
pub mod unwatch_repo;
|
||||||
|
pub mod update;
|
||||||
|
pub mod update_member_role;
|
||||||
|
pub mod update_protection_rule;
|
||||||
|
pub mod update_release;
|
||||||
|
pub mod update_webhook;
|
||||||
|
pub mod watch_repo;
|
||||||
|
|
||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
@@ -69,13 +69,22 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
.route("/{repo_name}", web::put().to(update::update))
|
.route("/{repo_name}", web::put().to(update::update))
|
||||||
.route("/{repo_name}", web::delete().to(delete::delete))
|
.route("/{repo_name}", web::delete().to(delete::delete))
|
||||||
.route("/{repo_name}/archive", web::post().to(archive::archive))
|
.route("/{repo_name}/archive", web::post().to(archive::archive))
|
||||||
.route("/{repo_name}/unarchive", web::post().to(unarchive::unarchive))
|
.route(
|
||||||
|
"/{repo_name}/unarchive",
|
||||||
|
web::post().to(unarchive::unarchive),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/transfer-owner",
|
"/{repo_name}/transfer-owner",
|
||||||
web::post().to(transfer_owner::transfer_owner),
|
web::post().to(transfer_owner::transfer_owner),
|
||||||
)
|
)
|
||||||
.route("/{repo_name}/branches", web::get().to(list_branches::list_branches))
|
.route(
|
||||||
.route("/{repo_name}/branches", web::post().to(create_branch::create_branch))
|
"/{repo_name}/branches",
|
||||||
|
web::get().to(list_branches::list_branches),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/branches",
|
||||||
|
web::post().to(create_branch::create_branch),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/branches/{branch_id}/default",
|
"/{repo_name}/branches/{branch_id}/default",
|
||||||
web::put().to(set_default_branch::set_default_branch),
|
web::put().to(set_default_branch::set_default_branch),
|
||||||
@@ -90,9 +99,18 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
)
|
)
|
||||||
.route("/{repo_name}/tags", web::get().to(list_tags::list_tags))
|
.route("/{repo_name}/tags", web::get().to(list_tags::list_tags))
|
||||||
.route("/{repo_name}/tags", web::post().to(create_tag::create_tag))
|
.route("/{repo_name}/tags", web::post().to(create_tag::create_tag))
|
||||||
.route("/{repo_name}/tags/{tag_id}", web::delete().to(delete_tag::delete_tag))
|
.route(
|
||||||
.route("/{repo_name}/releases", web::get().to(list_releases::list_releases))
|
"/{repo_name}/tags/{tag_id}",
|
||||||
.route("/{repo_name}/releases", web::post().to(create_release::create_release))
|
web::delete().to(delete_tag::delete_tag),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/releases",
|
||||||
|
web::get().to(list_releases::list_releases),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/releases",
|
||||||
|
web::post().to(create_release::create_release),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/releases/{release_id}",
|
"/{repo_name}/releases/{release_id}",
|
||||||
web::put().to(update_release::update_release),
|
web::put().to(update_release::update_release),
|
||||||
@@ -105,13 +123,31 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
.route("/{repo_name}/fork", web::post().to(fork_repo::fork_repo))
|
.route("/{repo_name}/fork", web::post().to(fork_repo::fork_repo))
|
||||||
.route("/{repo_name}/sync", web::post().to(sync_fork::sync_fork))
|
.route("/{repo_name}/sync", web::post().to(sync_fork::sync_fork))
|
||||||
.route("/{repo_name}/star", web::post().to(star_repo::star_repo))
|
.route("/{repo_name}/star", web::post().to(star_repo::star_repo))
|
||||||
.route("/{repo_name}/star", web::delete().to(unstar_repo::unstar_repo))
|
.route(
|
||||||
.route("/{repo_name}/stargazers", web::get().to(list_stargazers::list_stargazers))
|
"/{repo_name}/star",
|
||||||
|
web::delete().to(unstar_repo::unstar_repo),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/stargazers",
|
||||||
|
web::get().to(list_stargazers::list_stargazers),
|
||||||
|
)
|
||||||
.route("/{repo_name}/watch", web::post().to(watch_repo::watch_repo))
|
.route("/{repo_name}/watch", web::post().to(watch_repo::watch_repo))
|
||||||
.route("/{repo_name}/watch", web::delete().to(unwatch_repo::unwatch_repo))
|
.route(
|
||||||
.route("/{repo_name}/watchers", web::get().to(list_watchers::list_watchers))
|
"/{repo_name}/watch",
|
||||||
.route("/{repo_name}/members", web::get().to(list_members::list_members))
|
web::delete().to(unwatch_repo::unwatch_repo),
|
||||||
.route("/{repo_name}/members", web::post().to(add_member::add_member))
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/watchers",
|
||||||
|
web::get().to(list_watchers::list_watchers),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/members",
|
||||||
|
web::get().to(list_members::list_members),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/members",
|
||||||
|
web::post().to(add_member::add_member),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/members/{member_id}/role",
|
"/{repo_name}/members/{member_id}/role",
|
||||||
web::put().to(update_member_role::update_member_role),
|
web::put().to(update_member_role::update_member_role),
|
||||||
@@ -121,7 +157,10 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
web::delete().to(remove_member::remove_member),
|
web::delete().to(remove_member::remove_member),
|
||||||
)
|
)
|
||||||
.route("/{repo_name}/leave", web::post().to(leave_repo::leave_repo))
|
.route("/{repo_name}/leave", web::post().to(leave_repo::leave_repo))
|
||||||
.route("/{repo_name}/invitations", web::get().to(list_invitations::list_invitations))
|
.route(
|
||||||
|
"/{repo_name}/invitations",
|
||||||
|
web::get().to(list_invitations::list_invitations),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/invitations",
|
"/{repo_name}/invitations",
|
||||||
web::post().to(create_invitation::create_invitation),
|
web::post().to(create_invitation::create_invitation),
|
||||||
@@ -130,14 +169,26 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
"/{repo_name}/invitations/{invitation_id}",
|
"/{repo_name}/invitations/{invitation_id}",
|
||||||
web::delete().to(revoke_invitation::revoke_invitation),
|
web::delete().to(revoke_invitation::revoke_invitation),
|
||||||
)
|
)
|
||||||
.route("/{repo_name}/deploy-keys", web::get().to(list_deploy_keys::list_deploy_keys))
|
.route(
|
||||||
.route("/{repo_name}/deploy-keys", web::post().to(add_deploy_key::add_deploy_key))
|
"/{repo_name}/deploy-keys",
|
||||||
|
web::get().to(list_deploy_keys::list_deploy_keys),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/deploy-keys",
|
||||||
|
web::post().to(add_deploy_key::add_deploy_key),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/deploy-keys/{key_id}",
|
"/{repo_name}/deploy-keys/{key_id}",
|
||||||
web::delete().to(delete_deploy_key::delete_deploy_key),
|
web::delete().to(delete_deploy_key::delete_deploy_key),
|
||||||
)
|
)
|
||||||
.route("/{repo_name}/webhooks", web::get().to(list_webhooks::list_webhooks))
|
.route(
|
||||||
.route("/{repo_name}/webhooks", web::post().to(create_webhook::create_webhook))
|
"/{repo_name}/webhooks",
|
||||||
|
web::get().to(list_webhooks::list_webhooks),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/{repo_name}/webhooks",
|
||||||
|
web::post().to(create_webhook::create_webhook),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/{repo_name}/webhooks/{webhook_id}",
|
"/{repo_name}/webhooks/{webhook_id}",
|
||||||
web::put().to(update_webhook::update_webhook),
|
web::put().to(update_webhook::update_webhook),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoStats;
|
use crate::models::repos::RepoStats;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -20,7 +20,7 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Recalculates and updates repository statistics from the current state of the repository.
|
/// Recalculates and updates repository statistics from the current state of the repository.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Recalculates star, watcher, and fork counts
|
/// - Recalculates star, watcher, and fork counts
|
||||||
/// - Recalculates branch and tag counts
|
/// - Recalculates branch and tag counts
|
||||||
@@ -29,7 +29,7 @@ pub struct PathParams {
|
|||||||
/// - Recalculates open issues and pull requests count
|
/// - Recalculates open issues and pull requests count
|
||||||
/// - Updates storage size and bandwidth usage
|
/// - Updates storage size and bandwidth usage
|
||||||
/// - Updates last push timestamp
|
/// - Updates last push timestamp
|
||||||
///
|
///
|
||||||
/// Returns the refreshed statistics with all updated values.
|
/// Returns the refreshed statistics with all updated values.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,15 +21,15 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Revokes a user's access to the repository.
|
/// Revokes a user's access to the repository.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Restrictions:
|
/// Restrictions:
|
||||||
/// - Cannot remove the repository owner (use transfer_owner instead)
|
/// - Cannot remove the repository owner (use transfer_owner instead)
|
||||||
/// - Cannot remove members with equal or higher role than your own
|
/// - Cannot remove members with equal or higher role than your own
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Member loses all access to the repository
|
/// - Member loses all access to the repository
|
||||||
/// - Member is removed from all repository activities
|
/// - Member is removed from all repository activities
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -56,7 +56,12 @@ pub async fn remove_member(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_remove_member(&session, &path.workspace_name, &path.repo_name, path.member_id)
|
.repo_remove_member(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.member_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Member removed successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new("Member removed successfully".to_string())))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Marks a commit comment as resolved, indicating the issue has been addressed.
|
/// Marks a commit comment as resolved, indicating the issue has been addressed.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Comment is marked as resolved
|
/// - Comment is marked as resolved
|
||||||
/// - Resolved comments are visually distinguished in code review interfaces
|
/// - Resolved comments are visually distinguished in code review interfaces
|
||||||
/// - Resolution is recorded with the resolver's user ID and timestamp
|
/// - Resolution is recorded with the resolver's user ID and timestamp
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -53,8 +53,15 @@ pub async fn resolve_commit_comment(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_resolve_commit_comment(&session, &path.workspace_name, &path.repo_name, path.comment_id)
|
.repo_resolve_commit_comment(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.comment_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Commit comment resolved successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Commit comment resolved successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -21,12 +21,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Cancels a pending invitation, preventing the invitee from accepting it.
|
/// Cancels a pending invitation, preventing the invitee from accepting it.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Invitation is marked as revoked
|
/// - Invitation is marked as revoked
|
||||||
/// - Invitee can no longer accept the invitation
|
/// - Invitee can no longer accept the invitation
|
||||||
/// - Invitation email link becomes invalid
|
/// - Invitation email link becomes invalid
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -52,8 +52,15 @@ pub async fn revoke_invitation(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_revoke_invitation(&session, &path.workspace_name, &path.repo_name, path.invitation_id)
|
.repo_revoke_invitation(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.invitation_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Invitation revoked successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Invitation revoked successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::{IntoParams, ToSchema};
|
use utoipa::{IntoParams, ToSchema};
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -73,5 +73,7 @@ pub async fn set_branch_protection(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Branch protection rules set successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Branch protection rules set successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -23,9 +23,9 @@ pub struct PathParams {
|
|||||||
/// - New pull requests base branch
|
/// - New pull requests base branch
|
||||||
/// - Repository cloning
|
/// - Repository cloning
|
||||||
/// - New branch creation base
|
/// - New branch creation base
|
||||||
///
|
///
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
put,
|
put,
|
||||||
@@ -51,8 +51,15 @@ pub async fn set_default_branch(
|
|||||||
) -> Result<HttpResponse, AppError> {
|
) -> Result<HttpResponse, AppError> {
|
||||||
service
|
service
|
||||||
.repo
|
.repo
|
||||||
.repo_set_default_branch(&session, &path.workspace_name, &path.repo_name, path.branch_id)
|
.repo_set_default_branch(
|
||||||
|
&session,
|
||||||
|
&path.workspace_name,
|
||||||
|
&path.repo_name,
|
||||||
|
path.branch_id,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Default branch set successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Default branch set successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,12 +19,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Adds the current user to the repository's stargazers list.
|
/// Adds the current user to the repository's stargazers list.
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - User is added to the repository's stargazers
|
/// - User is added to the repository's stargazers
|
||||||
/// - Repository star count is incremented
|
/// - Repository star count is incremented
|
||||||
/// - User can unstar later to remove themselves
|
/// - User can unstar later to remove themselves
|
||||||
///
|
///
|
||||||
/// Returns success message on completion. Idempotent operation (starring an already starred repository is a no-op).
|
/// Returns success message on completion. Idempotent operation (starring an already starred repository is a no-op).
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
@@ -53,5 +53,7 @@ pub async fn star_repo(
|
|||||||
.repo_star(&session, &path.workspace_name, &path.repo_name)
|
.repo_star(&session, &path.workspace_name, &path.repo_name)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Repository starred successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Repository starred successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,12 +19,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Synchronizes a forked repository with the latest changes from the parent repository.
|
/// Synchronizes a forked repository with the latest changes from the parent repository.
|
||||||
/// Requires Write role or higher in the fork repository.
|
/// Requires Write role or higher in the fork repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Merges changes from the parent repository's default branch into the fork
|
/// - Merges changes from the parent repository's default branch into the fork
|
||||||
/// - Creates a merge commit if there are conflicts
|
/// - Creates a merge commit if there are conflicts
|
||||||
/// - Updates the fork's commit history
|
/// - Updates the fork's commit history
|
||||||
///
|
///
|
||||||
/// Only works on repositories that are forks (have a parent repository).
|
/// Only works on repositories that are forks (have a parent repository).
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
@@ -56,5 +56,7 @@ pub async fn sync_fork(
|
|||||||
.repo_sync_fork(&session, &path.workspace_name, &path.repo_name)
|
.repo_sync_fork(&session, &path.workspace_name, &path.repo_name)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Fork synchronized successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Fork synchronized successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::{IntoParams, ToSchema};
|
use utoipa::{IntoParams, ToSchema};
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
@@ -26,13 +26,13 @@ pub struct TransferOwnerParams {
|
|||||||
///
|
///
|
||||||
/// Transfers ownership of a repository to another user. The new owner must be an existing repository member.
|
/// Transfers ownership of a repository to another user. The new owner must be an existing repository member.
|
||||||
/// Requires Owner role in the repository.
|
/// Requires Owner role in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Current owner becomes an Admin
|
/// - Current owner becomes an Admin
|
||||||
/// - New owner gains full Owner permissions
|
/// - New owner gains full Owner permissions
|
||||||
/// - Repository URL remains unchanged
|
/// - Repository URL remains unchanged
|
||||||
/// - All forks and stars are preserved
|
/// - All forks and stars are preserved
|
||||||
///
|
///
|
||||||
/// Returns the updated repository with new owner information.
|
/// Returns the updated repository with new owner information.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,12 +19,12 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Restores an archived repository to active status, re-enabling all write operations.
|
/// Restores an archived repository to active status, re-enabling all write operations.
|
||||||
/// Requires Owner role in the repository.
|
/// Requires Owner role in the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - Repository status changes from "archived" to "active"
|
/// - Repository status changes from "archived" to "active"
|
||||||
/// - All write operations are re-enabled
|
/// - All write operations are re-enabled
|
||||||
/// - Previous visibility and settings are preserved
|
/// - Previous visibility and settings are preserved
|
||||||
///
|
///
|
||||||
/// Returns success message on completion.
|
/// Returns success message on completion.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,11 +19,11 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Removes the current user from the repository's stargazers list.
|
/// Removes the current user from the repository's stargazers list.
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - User is removed from the repository's stargazers
|
/// - User is removed from the repository's stargazers
|
||||||
/// - Repository star count is decremented
|
/// - Repository star count is decremented
|
||||||
///
|
///
|
||||||
/// Returns success message on completion. Idempotent operation (unstarring an unstarred repository is a no-op).
|
/// Returns success message on completion. Idempotent operation (unstarring an unstarred repository is a no-op).
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -52,5 +52,7 @@ pub async fn unstar_repo(
|
|||||||
.repo_unstar(&session, &path.workspace_name, &path.repo_name)
|
.repo_unstar(&session, &path.workspace_name, &path.repo_name)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Repository unstarred successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Repository unstarred successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
@@ -19,11 +19,11 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Removes the current user's watch subscription from the repository.
|
/// Removes the current user's watch subscription from the repository.
|
||||||
/// Requires read access to the repository.
|
/// Requires read access to the repository.
|
||||||
///
|
///
|
||||||
/// Effects:
|
/// Effects:
|
||||||
/// - User is removed from the repository's watchers
|
/// - User is removed from the repository's watchers
|
||||||
/// - User will no longer receive notifications for repository activities
|
/// - User will no longer receive notifications for repository activities
|
||||||
///
|
///
|
||||||
/// Returns success message on completion. Idempotent operation (unwatching an unwatched repository is a no-op).
|
/// Returns success message on completion. Idempotent operation (unwatching an unwatched repository is a no-op).
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
delete,
|
delete,
|
||||||
@@ -52,5 +52,7 @@ pub async fn unwatch_repo(
|
|||||||
.repo_unwatch(&session, &path.workspace_name, &path.repo_name)
|
.repo_unwatch(&session, &path.workspace_name, &path.repo_name)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ApiResponse::new("Repository watch subscription removed successfully".to_string())))
|
Ok(HttpResponse::Ok().json(ApiResponse::new(
|
||||||
|
"Repository watch subscription removed successfully".to_string(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::Repo;
|
use crate::models::repos::Repo;
|
||||||
use crate::service::repo::core::UpdateRepoParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::core::UpdateRepoParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -21,13 +21,13 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Updates repository metadata such as name, description, visibility, and default branch.
|
/// Updates repository metadata such as name, description, visibility, and default branch.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Update rules:
|
/// Update rules:
|
||||||
/// - name: Must be unique within workspace if changed (1-100 characters)
|
/// - name: Must be unique within workspace if changed (1-100 characters)
|
||||||
/// - description: Max 500 characters
|
/// - description: Max 500 characters
|
||||||
/// - visibility: "public", "private", or "internal" (workspace owners can restrict public repos)
|
/// - visibility: "public", "private", or "internal" (workspace owners can restrict public repos)
|
||||||
/// - default_branch: Must be an existing branch name
|
/// - default_branch: Must be an existing branch name
|
||||||
///
|
///
|
||||||
/// All fields are optional; only provided fields are updated.
|
/// All fields are optional; only provided fields are updated.
|
||||||
/// Returns the updated repository with full metadata.
|
/// Returns the updated repository with full metadata.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoMember;
|
use crate::models::repos::RepoMember;
|
||||||
use crate::service::repo::members::UpdateRepoMemberRoleParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::members::UpdateRepoMemberRoleParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -23,13 +23,13 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Changes the access level of an existing repository member.
|
/// Changes the access level of an existing repository member.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Role restrictions:
|
/// Role restrictions:
|
||||||
/// - Cannot change the owner's role (use transfer_owner instead)
|
/// - Cannot change the owner's role (use transfer_owner instead)
|
||||||
/// - Cannot assign "owner" role (use transfer_owner instead)
|
/// - Cannot assign "owner" role (use transfer_owner instead)
|
||||||
/// - Can only assign roles equal to or lower than your own
|
/// - Can only assign roles equal to or lower than your own
|
||||||
/// - Valid roles: "read", "write", "admin"
|
/// - Valid roles: "read", "write", "admin"
|
||||||
///
|
///
|
||||||
/// Returns the updated member record with new role information.
|
/// Returns the updated member record with new role information.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
put,
|
put,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::BranchProtectionRule;
|
use crate::models::repos::BranchProtectionRule;
|
||||||
use crate::service::repo::protection::UpdateProtectionRuleParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::protection::UpdateProtectionRuleParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -23,7 +23,7 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Updates an existing branch protection rule's configuration.
|
/// Updates an existing branch protection rule's configuration.
|
||||||
/// Requires Admin role or higher in the repository.
|
/// Requires Admin role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Updatable fields:
|
/// Updatable fields:
|
||||||
/// - required_approvals: Number of required approvals before merging (0-10)
|
/// - required_approvals: Number of required approvals before merging (0-10)
|
||||||
/// - require_status_checks: Whether status checks must pass
|
/// - require_status_checks: Whether status checks must pass
|
||||||
@@ -31,7 +31,7 @@ pub struct PathParams {
|
|||||||
/// - restrict_pushes: Restrict who can push to matching branches
|
/// - restrict_pushes: Restrict who can push to matching branches
|
||||||
/// - allow_force_pushes: Allow force pushes (only if restrict_pushes is false)
|
/// - allow_force_pushes: Allow force pushes (only if restrict_pushes is false)
|
||||||
/// - allow_deletions: Allow branch deletion (only if restrict_pushes is false)
|
/// - allow_deletions: Allow branch deletion (only if restrict_pushes is false)
|
||||||
///
|
///
|
||||||
/// All fields are optional; only provided fields are updated.
|
/// All fields are optional; only provided fields are updated.
|
||||||
/// Returns the updated protection rule with full configuration.
|
/// Returns the updated protection rule with full configuration.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use utoipa::IntoParams;
|
use utoipa::IntoParams;
|
||||||
|
|
||||||
use crate::api::response::{ApiResponse, ApiErrorResponse};
|
use crate::api::response::{ApiErrorResponse, ApiResponse};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::models::repos::RepoRelease;
|
use crate::models::repos::RepoRelease;
|
||||||
use crate::service::repo::releases::UpdateReleaseParams;
|
|
||||||
use crate::service::AppService;
|
use crate::service::AppService;
|
||||||
|
use crate::service::repo::releases::UpdateReleaseParams;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, IntoParams)]
|
#[derive(Debug, Deserialize, IntoParams)]
|
||||||
@@ -23,13 +23,13 @@ pub struct PathParams {
|
|||||||
///
|
///
|
||||||
/// Updates release metadata such as name, description, draft status, and prerelease flag.
|
/// Updates release metadata such as name, description, draft status, and prerelease flag.
|
||||||
/// Requires Write role or higher in the repository.
|
/// Requires Write role or higher in the repository.
|
||||||
///
|
///
|
||||||
/// Updatable fields:
|
/// Updatable fields:
|
||||||
/// - name: Release name/title (max 255 characters)
|
/// - name: Release name/title (max 255 characters)
|
||||||
/// - body: Release notes in markdown format (max 10000 characters)
|
/// - body: Release notes in markdown format (max 10000 characters)
|
||||||
/// - draft: Whether this is a draft release
|
/// - draft: Whether this is a draft release
|
||||||
/// - prerelease: Whether this is a prerelease
|
/// - prerelease: Whether this is a prerelease
|
||||||
///
|
///
|
||||||
/// All fields are optional; only provided fields are updated.
|
/// All fields are optional; only provided fields are updated.
|
||||||
/// Returns the updated release with full metadata.
|
/// Returns the updated release with full metadata.
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user