mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-11 19:00:36 +08:00
345 lines
8.8 KiB
Rust
345 lines
8.8 KiB
Rust
use std::ops::Deref;
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use axum::extract::State;
|
|
use axum::response::{IntoResponse, Json};
|
|
use axum::routing::post;
|
|
use axum::Router;
|
|
use hyper::header::CONTENT_TYPE;
|
|
use hyper::Method;
|
|
use radicle::cob::TypeName;
|
|
use serde::{Deserialize, Serialize};
|
|
use tower_http::cors::{self, CorsLayer};
|
|
|
|
use radicle::{git, identity};
|
|
use radicle_types as types;
|
|
use radicle_types::cobs::issue::{Action, NewIssue};
|
|
use radicle_types::cobs::CobOptions;
|
|
use radicle_types::error::Error;
|
|
use radicle_types::traits::auth::Auth;
|
|
use radicle_types::traits::cobs::Cobs;
|
|
use radicle_types::traits::issue::{Issues, IssuesMut};
|
|
use radicle_types::traits::patch::{Patches, PatchesMut};
|
|
use radicle_types::traits::repo::{Repo, Show};
|
|
use radicle_types::traits::thread::Thread;
|
|
use radicle_types::traits::Profile;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Context {
|
|
profile: Arc<radicle::Profile>,
|
|
}
|
|
|
|
impl Auth for Context {}
|
|
impl Repo for Context {}
|
|
impl Cobs for Context {}
|
|
impl Thread for Context {}
|
|
impl Issues for Context {}
|
|
impl IssuesMut for Context {}
|
|
impl Patches for Context {}
|
|
impl PatchesMut for Context {}
|
|
impl Profile for Context {
|
|
fn profile(&self) -> radicle::Profile {
|
|
self.profile.deref().clone()
|
|
}
|
|
}
|
|
|
|
impl Context {
|
|
pub fn new(profile: Arc<radicle::Profile>) -> Self {
|
|
Self { profile }
|
|
}
|
|
}
|
|
|
|
pub fn router(ctx: Context) -> Router {
|
|
Router::new()
|
|
.route("/config", post(config_handler))
|
|
.route("/authenticate", post(auth_handler))
|
|
.route("/list_repos", post(repo_root_handler))
|
|
.route("/repo_by_id", post(repo_handler))
|
|
.route("/diff_stats", post(diff_stats_handler))
|
|
.route("/activity_by_id", post(activity_handler))
|
|
.route("/get_diff", post(diff_handler))
|
|
.route("/list_issues", post(issues_handler))
|
|
.route("/create_issue", post(create_issue_handler))
|
|
.route("/create_issue_comment", post(create_issue_comment_handler))
|
|
.route("/edit_issue", post(edit_issue_handler))
|
|
.route("/issue_by_id", post(issue_handler))
|
|
.route("/comment_threads_by_issue_id", post(issue_threads_handler))
|
|
.route("/list_patches", post(patches_handler))
|
|
.route("/patch_by_id", post(patch_handler))
|
|
.route("/revisions_by_patch", post(revision_handler))
|
|
.route("/get_embed", post(get_embeds_handler))
|
|
.route("/save_embed_by_path", post(save_embed_handler))
|
|
.route("/save_embed_by_clipboard", post(save_embed_handler))
|
|
.route("/save_embed_by_bytes", post(save_embed_handler))
|
|
.route("/save_embed_to_disk", post(save_embed_handler))
|
|
.layer(
|
|
CorsLayer::new()
|
|
.allow_origin(cors::Any)
|
|
.allow_methods([Method::POST, Method::GET])
|
|
.allow_headers([CONTENT_TYPE]),
|
|
)
|
|
.with_state(ctx)
|
|
}
|
|
|
|
async fn config_handler(State(ctx): State<Context>) -> impl IntoResponse {
|
|
let config = ctx.config();
|
|
|
|
Ok::<_, Error>(Json(config))
|
|
}
|
|
|
|
async fn auth_handler(State(ctx): State<Context>) -> impl IntoResponse {
|
|
ctx.authenticate()?;
|
|
|
|
Ok::<_, Error>(Json(()))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct Options {
|
|
show: Show,
|
|
}
|
|
|
|
async fn repo_root_handler(
|
|
State(ctx): State<Context>,
|
|
Json(Options { show }): Json<Options>,
|
|
) -> impl IntoResponse {
|
|
let repos = ctx.list_repos(show)?;
|
|
|
|
Ok::<_, Error>(Json(repos))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct RepoBody {
|
|
pub rid: identity::RepoId,
|
|
}
|
|
|
|
async fn repo_handler(
|
|
State(ctx): State<Context>,
|
|
Json(RepoBody { rid }): Json<RepoBody>,
|
|
) -> impl IntoResponse {
|
|
let info = ctx.repo_by_id(rid)?;
|
|
|
|
Ok::<_, Error>(Json(info))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct DiffStatsBody {
|
|
pub rid: identity::RepoId,
|
|
pub base: git::Oid,
|
|
pub head: git::Oid,
|
|
}
|
|
|
|
async fn diff_stats_handler(
|
|
State(ctx): State<Context>,
|
|
Json(DiffStatsBody { rid, base, head }): Json<DiffStatsBody>,
|
|
) -> impl IntoResponse {
|
|
let info = ctx.diff_stats(rid, base, head)?;
|
|
|
|
Ok::<_, Error>(Json(info))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct DiffBody {
|
|
pub rid: identity::RepoId,
|
|
pub options: types::cobs::diff::Options,
|
|
}
|
|
|
|
async fn diff_handler(
|
|
State(ctx): State<Context>,
|
|
Json(DiffBody { rid, options }): Json<DiffBody>,
|
|
) -> impl IntoResponse {
|
|
let info = ctx.get_diff(rid, options)?;
|
|
|
|
Ok::<_, Error>(Json(info))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct IssuesBody {
|
|
pub rid: identity::RepoId,
|
|
pub status: Option<types::cobs::query::IssueStatus>,
|
|
}
|
|
|
|
async fn issues_handler(
|
|
State(ctx): State<Context>,
|
|
Json(IssuesBody { rid, status }): Json<IssuesBody>,
|
|
) -> impl IntoResponse {
|
|
let issues = ctx.list_issues(rid, status)?;
|
|
|
|
Ok::<_, Error>(Json(issues))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct CreateIssuesBody {
|
|
pub rid: identity::RepoId,
|
|
pub opts: CobOptions,
|
|
pub new: NewIssue,
|
|
}
|
|
|
|
async fn create_issue_handler(
|
|
State(ctx): State<Context>,
|
|
Json(CreateIssuesBody { rid, opts, new }): Json<CreateIssuesBody>,
|
|
) -> impl IntoResponse {
|
|
let issues = ctx.create_issue(rid, new, opts)?;
|
|
|
|
Ok::<_, Error>(Json(issues))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct CreateIssueCommentBody {
|
|
pub rid: identity::RepoId,
|
|
pub new: types::cobs::thread::NewIssueComment,
|
|
pub opts: types::cobs::CobOptions,
|
|
}
|
|
|
|
async fn create_issue_comment_handler(
|
|
State(ctx): State<Context>,
|
|
Json(CreateIssueCommentBody { rid, opts, new }): Json<CreateIssueCommentBody>,
|
|
) -> impl IntoResponse {
|
|
let comment = ctx.create_issue_comment(rid, new, opts)?;
|
|
|
|
Ok::<_, Error>(Json(comment))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct EditIssuesBody {
|
|
pub rid: identity::RepoId,
|
|
pub cob_id: git::Oid,
|
|
pub action: Action,
|
|
pub opts: CobOptions,
|
|
}
|
|
|
|
async fn edit_issue_handler(
|
|
State(ctx): State<Context>,
|
|
Json(EditIssuesBody {
|
|
rid,
|
|
cob_id,
|
|
action,
|
|
opts,
|
|
}): Json<EditIssuesBody>,
|
|
) -> impl IntoResponse {
|
|
let issues = ctx.edit_issue(rid, cob_id, action, opts)?;
|
|
|
|
Ok::<_, Error>(Json(issues))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct ActivityBody {
|
|
pub rid: identity::RepoId,
|
|
pub type_name: TypeName,
|
|
pub id: git::Oid,
|
|
}
|
|
|
|
async fn activity_handler(
|
|
State(ctx): State<Context>,
|
|
Json(ActivityBody { rid, type_name, id }): Json<ActivityBody>,
|
|
) -> impl IntoResponse {
|
|
let activity = ctx.activity_by_id(rid, type_name, id)?;
|
|
|
|
Ok::<_, Error>(Json(activity))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct EmbedBody {
|
|
pub rid: identity::RepoId,
|
|
pub name: Option<String>,
|
|
pub oid: git::Oid,
|
|
}
|
|
|
|
async fn get_embeds_handler(
|
|
State(ctx): State<Context>,
|
|
Json(EmbedBody { rid, name, oid }): Json<EmbedBody>,
|
|
) -> impl IntoResponse {
|
|
let embed = ctx.get_embed(rid, name, oid)?;
|
|
|
|
Ok::<_, Error>(Json(embed))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct CreateEmbedBody {
|
|
pub rid: identity::RepoId,
|
|
pub path: PathBuf,
|
|
}
|
|
|
|
async fn save_embed_handler(
|
|
State(ctx): State<Context>,
|
|
Json(CreateEmbedBody { rid, path }): Json<CreateEmbedBody>,
|
|
) -> impl IntoResponse {
|
|
let embed = ctx.save_embed_by_path(rid, path)?;
|
|
|
|
Ok::<_, Error>(Json(embed))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct IssueBody {
|
|
pub rid: identity::RepoId,
|
|
pub id: git::Oid,
|
|
}
|
|
|
|
async fn issue_handler(
|
|
State(ctx): State<Context>,
|
|
Json(IssueBody { rid, id }): Json<IssueBody>,
|
|
) -> impl IntoResponse {
|
|
let issue = ctx.issue_by_id(rid, id)?;
|
|
|
|
Ok::<_, Error>(Json(issue))
|
|
}
|
|
|
|
async fn issue_threads_handler(
|
|
State(ctx): State<Context>,
|
|
Json(IssueBody { rid, id }): Json<IssueBody>,
|
|
) -> impl IntoResponse {
|
|
let issue_threads = ctx.comment_threads_by_issue_id(rid, id)?;
|
|
|
|
Ok::<_, Error>(Json(issue_threads))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct PatchesBody {
|
|
pub rid: identity::RepoId,
|
|
pub skip: Option<usize>,
|
|
pub take: Option<usize>,
|
|
pub status: Option<types::cobs::query::PatchStatus>,
|
|
}
|
|
|
|
async fn patches_handler(
|
|
State(ctx): State<Context>,
|
|
Json(PatchesBody {
|
|
rid,
|
|
skip,
|
|
take,
|
|
status,
|
|
}): Json<PatchesBody>,
|
|
) -> impl IntoResponse {
|
|
let patches = ctx.list_patches(rid, status, skip, take)?;
|
|
|
|
Ok::<_, Error>(Json(patches))
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct PatchBody {
|
|
pub rid: identity::RepoId,
|
|
pub id: git::Oid,
|
|
}
|
|
|
|
async fn patch_handler(
|
|
State(ctx): State<Context>,
|
|
Json(PatchBody { rid, id }): Json<PatchBody>,
|
|
) -> impl IntoResponse {
|
|
let patch = ctx.get_patch(rid, id)?;
|
|
|
|
Ok::<_, Error>(Json(patch))
|
|
}
|
|
|
|
async fn revision_handler(
|
|
State(ctx): State<Context>,
|
|
Json(PatchBody { rid, id }): Json<PatchBody>,
|
|
) -> impl IntoResponse {
|
|
let revisions = ctx.revisions_by_patch(rid, id)?;
|
|
|
|
Ok::<_, Error>(Json(revisions))
|
|
}
|