From 3e07808ee53edd9d64ef6c36ecb05a716fa9f374 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Mon, 27 Nov 2023 13:34:16 +0100 Subject: [PATCH] httpd: Add node policies endpoint New endpoint on `PUT api/v1/node/policies/repos/:rid` and `DELETE api/v1/node/policies/repos/:rid`, that allows to track and untrack a project. For tracking a project we also accept `?from=` to specify where we should fetch from after tracking a repo. --- radicle-httpd/src/api.rs | 11 ++++++- radicle-httpd/src/api/v1/node.rs | 56 ++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/radicle-httpd/src/api.rs b/radicle-httpd/src/api.rs index 4753691b..dcf3200f 100644 --- a/radicle-httpd/src/api.rs +++ b/radicle-httpd/src/api.rs @@ -19,7 +19,8 @@ use radicle::cob::{issue, Uri}; use radicle::cob::{patch, Embed}; use radicle::identity::{DocAt, Id}; use radicle::node::routing::Store; -use radicle::node::Handle; +use radicle::node::tracking::Scope; +use radicle::node::{Handle, NodeId}; use radicle::storage::{Oid, ReadRepository, ReadStorage}; use radicle::{Node, Profile}; @@ -143,6 +144,14 @@ pub struct CobsQuery { pub state: Option, } +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoliciesQuery { + /// The NID from which to fetch from after tracking a repo. + pub from: Option, + pub scope: Option, +} + #[derive(Default, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub enum IssueState { diff --git a/radicle-httpd/src/api/v1/node.rs b/radicle-httpd/src/api/v1/node.rs index 5da0dfdd..f1e47944 100644 --- a/radicle-httpd/src/api/v1/node.rs +++ b/radicle-httpd/src/api/v1/node.rs @@ -1,19 +1,27 @@ use axum::extract::State; use axum::response::IntoResponse; -use axum::routing::get; +use axum::routing::{get, put}; use axum::{Json, Router}; +use axum_auth::AuthBearer; +use hyper::StatusCode; use serde_json::json; -use radicle::node::{tracking, Handle}; +use radicle::identity::Id; +use radicle::node::{tracking, Handle, DEFAULT_TIMEOUT}; use radicle::Node; use crate::api::error::Error; -use crate::api::Context; +use crate::api::{self, Context, PoliciesQuery}; +use crate::axum_extra::{Path, Query}; pub fn router(ctx: Context) -> Router { Router::new() .route("/node", get(node_handler)) - .route("/node/tracking/repos", get(node_tracking_repos_handler)) + .route("/node/policies/repos", get(node_policies_repos_handler)) + .route( + "/node/policies/repos/:rid", + put(node_policies_track_handler).delete(node_policies_untrack_handler), + ) .with_state(ctx) } @@ -44,8 +52,8 @@ async fn node_handler(State(ctx): State) -> impl IntoResponse { } /// Return local tracking repos information. -/// `GET /node/tracking/repos` -async fn node_tracking_repos_handler(State(ctx): State) -> impl IntoResponse { +/// `GET /node/policies/repos` +async fn node_policies_repos_handler(State(ctx): State) -> impl IntoResponse { let tracking = ctx.profile.tracking()?; let mut repos = Vec::new(); @@ -59,3 +67,39 @@ async fn node_tracking_repos_handler(State(ctx): State) -> impl IntoRes Ok::<_, Error>(Json(repos)) } + +/// Track a new repo. +/// `PUT /node/policies/repos/:rid` +async fn node_policies_track_handler( + State(ctx): State, + AuthBearer(token): AuthBearer, + Path(project): Path, + Query(qs): Query, +) -> impl IntoResponse { + api::auth::validate(&ctx, &token).await?; + let mut node = Node::new(ctx.profile.socket()); + node.track_repo(project, qs.scope.unwrap_or_default())?; + if let Some(from) = qs.from { + let results = node.fetch(project, from, DEFAULT_TIMEOUT)?; + return Ok::<_, Error>(( + StatusCode::OK, + Json(json!({ "success": true, "results": results })), + )); + } + + Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true })))) +} + +/// Untrack a repo. +/// `DELETE /node/policies/repos/:rid` +async fn node_policies_untrack_handler( + State(ctx): State, + AuthBearer(token): AuthBearer, + Path(project): Path, +) -> impl IntoResponse { + api::auth::validate(&ctx, &token).await?; + let mut node = Node::new(ctx.profile.socket()); + node.untrack_repo(project)?; + + Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true })))) +}