diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index c0b5d8ddb..dc09c90b4 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -11,7 +11,7 @@ use aide::axum::{ routing::{get_with, post_with}, }; use axum::extract::{FromRef, FromRequestParts}; -use mas_data_model::{BoxRng, SiteConfig}; +use mas_data_model::{AppVersion, BoxRng, SiteConfig}; use mas_matrix::HomeserverConnection; use mas_policy::PolicyFactory; @@ -28,6 +28,7 @@ mod user_emails; mod user_registration_tokens; mod user_sessions; mod users; +mod version; pub fn router() -> ApiRouter where @@ -35,6 +36,7 @@ where Arc: FromRef, PasswordManager: FromRef, SiteConfig: FromRef, + AppVersion: FromRef, Arc: FromRef, BoxRng: FromRequestParts, CallContext: FromRequestParts, @@ -44,6 +46,10 @@ where "/site-config", get_with(self::site_config::handler, self::site_config::doc), ) + .api_route( + "/version", + get_with(self::version::handler, self::version::doc), + ) .api_route( "/compat-sessions", get_with(self::compat_sessions::list, self::compat_sessions::list_doc), diff --git a/crates/handlers/src/admin/v1/version.rs b/crates/handlers/src/admin/v1/version.rs new file mode 100644 index 000000000..2fe53940b --- /dev/null +++ b/crates/handlers/src/admin/v1/version.rs @@ -0,0 +1,62 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::transform::TransformOperation; +use axum::{Json, extract::State}; +use mas_data_model::AppVersion; +use schemars::JsonSchema; +use serde::Serialize; + +use crate::admin::call_context::CallContext; + +#[derive(Serialize, JsonSchema)] +pub struct Version { + /// The semver version of the app + pub version: &'static str, +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("version") + .tag("server") + .summary("Get the version currently running") + .response_with::<200, Json, _>(|t| t.example(Version { version: "v1.0.0" })) +} + +#[tracing::instrument(name = "handler.admin.v1.version", skip_all)] +pub async fn handler( + _: CallContext, + State(AppVersion(version)): State, +) -> Json { + Json(Version { version }) +} + +#[cfg(test)] +mod tests { + use hyper::{Request, StatusCode}; + use insta::assert_json_snapshot; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_add_user(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + let request = Request::get("/api/admin/v1/version").bearer(&token).empty(); + + let response = state.request(request).await; + + assert_eq!(response.status(), StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "version": "v0.0.0-test" + } + "#); + } +} diff --git a/docs/api/spec.json b/docs/api/spec.json index 98f8b2532..74e42f734 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -50,6 +50,30 @@ } } }, + "/api/admin/v1/version": { + "get": { + "tags": [ + "server" + ], + "summary": "Get the version currently running", + "operationId": "version", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Version" + }, + "example": { + "version": "v1.0.0" + } + } + } + } + } + } + }, "/api/admin/v1/compat-sessions": { "get": { "tags": [ @@ -3710,6 +3734,18 @@ } } }, + "Version": { + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "description": "The semver version of the app", + "type": "string" + } + } + }, "PaginationParams": { "type": "object", "properties": {