Add relay activity

This commit is contained in:
Jon Staab
2026-03-27 15:24:08 -07:00
parent 6510bc0d85
commit 77365f74ee
10 changed files with 152 additions and 6 deletions
+8
View File
@@ -32,11 +32,13 @@ Notes:
## `async fn list_plans(...) -> Response`
- Serves `GET /plans`
- No authentication required
- Return `data` is a list of plan structs from `Repo::list_plans`
## `async fn get_plan(...) -> Response`
- Serves `GET /plans/:id`
- No authentication required
- Return `data` is a single plan struct matching `id`
- If plan does not exist, return `404` with `code=not-found`
@@ -114,6 +116,12 @@ Notes:
- If relay is a duplicate by subdomain, return a `422` with `code=subdomain-exists`
- Return `data` is a single relay struct.
## `async fn list_relay_activity(...) -> Response`
- Serves `GET /relays/:id/activity`
- Authorizes admin or relay owner
- Return `data` is a list of activity structs from `repo.list_activity_for_relay`
## `async fn deactivate_relay(...) -> Response`
- Serves `POST /relays/:id/deactivate`
+5
View File
@@ -138,6 +138,11 @@ Notes:
- Returns all activity occuring after `since` matching `tenant`
## `pub fn list_activity_for_relay(&self, relay_id: &str) -> Result<Vec<Activity>>`
- Returns all activity where `resource_type = 'relay'` and `resource_id = relay_id`
- Ordered newest-first
## `pub fn get_relay_plan_sats(&self, plan: &str) -> Result<i64>`
- Returns the monthly sats amount for a given plan id
+22
View File
@@ -110,6 +110,7 @@ impl Api {
.route("/tenants/:pubkey/billing", put(update_tenant_billing))
.route("/relays", get(list_relays).post(create_relay))
.route("/relays/:id", get(get_relay).put(update_relay))
.route("/relays/:id/activity", get(list_relay_activity))
.route("/relays/:id/deactivate", post(deactivate_relay))
.route("/invoices", get(list_invoices))
.route("/invoices/:id", get(get_invoice))
@@ -472,6 +473,27 @@ async fn get_relay(
Ok(ok(StatusCode::OK, relay))
}
async fn list_relay_activity(
State(state): State<AppState>,
headers: HeaderMap,
Path(id): Path<String>,
) -> std::result::Result<Response, ApiError> {
let auth = state.api.extract_auth_pubkey(&headers)?;
let relay = match state.api.repo.get_relay(&id).await {
Ok(Some(r)) => r,
Ok(None) => return Ok(err(StatusCode::NOT_FOUND, "not-found", "relay not found")),
Err(e) => return Ok(err(StatusCode::INTERNAL_SERVER_ERROR, "internal", &e.to_string())),
};
state.api.require_admin_or_tenant(&auth, &relay.tenant)?;
match state.api.repo.list_activity_for_relay(&id).await {
Ok(activity) => Ok(ok(StatusCode::OK, activity)),
Err(e) => Ok(err(StatusCode::INTERNAL_SERVER_ERROR, "internal", &e.to_string())),
}
}
async fn create_relay(
State(state): State<AppState>,
headers: HeaderMap,
+13
View File
@@ -499,6 +499,19 @@ impl Repo {
Ok(rows)
}
pub async fn list_activity_for_relay(&self, relay_id: &str) -> Result<Vec<Activity>> {
let rows = sqlx::query_as::<_, Activity>(
"SELECT id, tenant, created_at, activity_type, resource_type, resource_id
FROM activity
WHERE resource_type = 'relay' AND resource_id = ?
ORDER BY created_at DESC, id DESC",
)
.bind(relay_id)
.fetch_all(&self.pool)
.await?;
Ok(rows)
}
pub async fn get_invoice_items(&self, invoice_id: &str) -> Result<Vec<InvoiceItem>> {
let rows = sqlx::query_as::<_, InvoiceItem>(
"SELECT id, invoice, relay, sats