Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
http: Only count publicly seeded repositories
Draft rudolfs opened 1 year ago

Previously the /api/v1/stats endpoint would count any repository that is in the storage regardless of whether the repository is publicly seeded or not.

check check-visual check-unit-test check-http-client-unit-test check-radicle-httpd check-e2e check-build check-http 👉 Preview 👉 Workflow runs 👉 Branch on GitHub

5 files changed +59 -19 6f134ca6 13850510
modified radicle-httpd/src/api/v1/delegates.rs
@@ -167,7 +167,7 @@ mod routes {
                  "closed": 0,
                },
                "id": RID,
-
                "seeding": 0,
+
                "seeding": 1,
              },
              {
                "name": "again-hello-world",
@@ -195,7 +195,7 @@ mod routes {
                  "closed": 0,
                },
                "id": "rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE",
-
                "seeding": 0,
+
                "seeding": 1,
              }
            ])
        );
@@ -245,7 +245,7 @@ mod routes {
                  "closed": 0,
                },
                "id": RID,
-
                "seeding": 0,
+
                "seeding": 1,
              },
              {
                "name": "again-hello-world",
@@ -273,7 +273,7 @@ mod routes {
                  "closed": 0,
                },
                "id": "rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE",
-
                "seeding": 0,
+
                "seeding": 1,
              }
            ])
        );
modified radicle-httpd/src/api/v1/node.rs
@@ -112,7 +112,7 @@ mod routes {
    use axum::extract::connect_info::MockConnectInfo;
    use axum::http::StatusCode;
    use pretty_assertions::assert_eq;
-
    use serde_json::json;
+
    use serde_json::{json, Value};

    use crate::test::*;

@@ -206,6 +206,21 @@ mod routes {
        let response = get(&app, format!("/nodes/{nid}/inventory")).await;

        assert_eq!(response.status(), StatusCode::OK);
-
        assert_eq!(response.json().await, json!([]));
+
        let json_response = response.json().await;
+

+
        let mut arr = match json_response {
+
            Value::Array(arr) => arr,
+
            _ => panic!("Expected JSON array in response"),
+
        };
+

+
        arr.sort_by(|a, b| a.as_str().cmp(&b.as_str()));
+

+
        assert_eq!(
+
            arr,
+
            vec![
+
                json!("rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp"),
+
                json!("rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE"),
+
            ]
+
        );
    }
}
modified radicle-httpd/src/api/v1/projects.rs
@@ -760,7 +760,7 @@ mod routes {
                  "closed": 0,
                },
                "id": RID,
-
                "seeding": 0,
+
                "seeding": 1,
              },
              {
                "name": "again-hello-world",
@@ -788,7 +788,7 @@ mod routes {
                  "closed": 0,
                },
                "id": "rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE",
-
                "seeding": 0,
+
                "seeding": 1,
              },
            ])
        );
@@ -829,7 +829,7 @@ mod routes {
                  "closed": 0,
                },
                "id": RID,
-
                "seeding": 0,
+
                "seeding": 1,
              },
              {
                "name": "again-hello-world",
@@ -857,7 +857,7 @@ mod routes {
                  "closed": 0,
                },
                "id": "rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE",
-
                "seeding": 0,
+
                "seeding": 1,
              },
            ])
        );
@@ -898,7 +898,7 @@ mod routes {
                 "closed": 0,
               },
               "id": RID,
-
               "seeding": 0,
+
               "seeding": 1,
            })
        );
    }
@@ -924,7 +924,7 @@ mod routes {
                    "alias": CONTRIBUTOR_ALIAS
                  }
                ],
-
                "seeds": 0,
+
                "seeds": 1,
              },
              {
                "rid": "rad:z4GypKmh1gkEfmkXtarcYnkvtFUfE",
@@ -937,7 +937,7 @@ mod routes {
                    "alias": CONTRIBUTOR_ALIAS
                  },
                ],
-
                "seeds": 0,
+
                "seeds": 1,
              },
            ])
        );
@@ -964,7 +964,7 @@ mod routes {
                    "alias": CONTRIBUTOR_ALIAS,
                  }
                ],
-
                "seeds": 0,
+
                "seeds": 1,
              },
            ])
        );
modified radicle-httpd/src/api/v1/stats.rs
@@ -4,7 +4,7 @@ use axum::routing::get;
use axum::{Json, Router};
use serde_json::json;

-
use radicle::storage::ReadStorage;
+
use radicle::node::routing::Store;

use crate::api::error::Error;
use crate::api::Context;
@@ -18,9 +18,12 @@ pub fn router(ctx: Context) -> Router {
/// Return the stats for the node.
/// `GET /stats`
async fn stats_handler(State(ctx): State<Context>) -> impl IntoResponse {
-
    let total = ctx.profile.storage.repositories()?.len();
+
    let db = &ctx.profile.database()?;
+
    let nid = ctx.profile.public_key;

-
    Ok::<_, Error>(Json(json!({ "repos": { "total": total } })))
+
    let total_seeded = db.get_inventory(&nid)?.len();
+

+
    Ok::<_, Error>(Json(json!({ "repos": { "total": total_seeded } })))
}

#[cfg(test)]
@@ -37,6 +40,6 @@ mod routes {
        let response = get(&app, "/stats").await;

        assert_eq!(response.status(), StatusCode::OK);
-
        assert_eq!(response.json().await, json!({ "repos": { "total": 3 } }));
+
        assert_eq!(response.json().await, json!({ "repos": { "total": 2 } }));
    }
}
modified radicle-httpd/src/test.rs
@@ -7,6 +7,7 @@ use std::sync::Arc;
use axum::body::{Body, Bytes};
use axum::http::{Method, Request};
use axum::Router;
+
use radicle::node::{Features, Timestamp, UserAgent};
use serde_json::Value;
use tower::ServiceExt;

@@ -17,8 +18,8 @@ use radicle::git::{raw as git2, RefString};
use radicle::identity::Visibility;
use radicle::profile::{env, Home};
use radicle::storage::ReadStorage;
-
use radicle::Storage;
use radicle::{node, profile};
+
use radicle::{Node, Storage};
use radicle_crypto::test::signer::MockSigner;

use crate::api::Context;
@@ -52,6 +53,18 @@ pub fn profile(home: &Path, seed: [u8; 32]) -> radicle::Profile {
    let mut db = home.policies_mut().unwrap();
    db.follow(&keypair.pk.into(), Some(&alias)).unwrap();

+
    let node_db = home.database_mut().unwrap();
+
    node_db
+
        .init(
+
            &keypair.pk.into(),
+
            Features::SEED,
+
            &alias,
+
            &UserAgent::default(),
+
            Timestamp::try_from(TIMESTAMP).unwrap(),
+
            [],
+
        )
+
        .unwrap();
+

    radicle::storage::git::transport::local::register(storage.clone());
    keystore.store(keypair.clone(), "radicle", None).unwrap();

@@ -216,6 +229,11 @@ fn seed_with_signer<G: Signer>(dir: &Path, profile: radicle::Profile, signer: &G
    )
    .unwrap();
    policies.seed(&rid, node::policy::Scope::All).unwrap();
+
    let node_handle = &mut Node::new(profile.socket());
+
    profile
+
        .seed(rid, node::policy::Scope::All, node_handle)
+
        .unwrap();
+
    profile.add_inventory(rid, node_handle).unwrap();

    let storage = &profile.storage;
    let repo = storage.repository(rid).unwrap();
@@ -291,6 +309,10 @@ fn seed_with_signer<G: Signer>(dir: &Path, profile: radicle::Profile, signer: &G
    )
    .unwrap();
    policies.seed(&rid, node::policy::Scope::Followed).unwrap();
+
    profile
+
        .seed(rid, node::policy::Scope::Followed, node_handle)
+
        .unwrap();
+
    profile.add_inventory(rid, node_handle).unwrap();

    let options = crate::Options {
        aliases: std::collections::HashMap::new(),