mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Add OpenAPI documentation via Utoipa
Annotates all API handlers and model structs with Utoipa macros to generate an OpenAPI 3.0 spec at runtime. Serves an interactive Swagger UI at /api/docs and the raw JSON spec at /api/docs/openapi.json, both publicly accessible outside the auth middleware. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6002597383
commit
44d593fccc
Generated
+191
-1
@@ -91,6 +91,15 @@ version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
@@ -193,6 +202,12 @@ version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -416,6 +431,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.4"
|
||||
@@ -480,6 +504,17 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -612,6 +647,16 @@ version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"miniz_oxide",
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -1398,6 +1443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1553,6 +1599,8 @@ dependencies = [
|
||||
"tokio 1.49.0",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2032,7 +2080,7 @@ version = "0.10.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.13.1",
|
||||
"bytes 0.5.6",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@@ -2113,6 +2161,40 @@ dependencies = [
|
||||
"rusqlite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"syn",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.21.3"
|
||||
@@ -2163,6 +2245,15 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.28"
|
||||
@@ -2351,6 +2442,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
@@ -2985,6 +3082,48 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "5.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bde15df68e80b16c7d16b9616e80770ad158988daa56a27dccd1e55558b0160"
|
||||
dependencies = [
|
||||
"indexmap 2.13.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"utoipa-gen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "5.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba0b99ee52df3028635d93840c797102da61f8a7bb3cf751032455895b52ef8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "9.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
"utoipa",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.21.0"
|
||||
@@ -3009,6 +3148,16 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
@@ -3175,6 +3324,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -3553,8 +3711,40 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"indexmap 2.13.0",
|
||||
"memchr",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"log",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
@@ -26,3 +26,5 @@ r2d2 = "0.8.10"
|
||||
r2d2_sqlite = "0.32.0"
|
||||
once_cell = "1.21.3"
|
||||
tower = "0.5.3"
|
||||
utoipa = { version = "5", features = ["axum_extras", "chrono"] }
|
||||
utoipa-swagger-ui = { version = "9", features = ["axum"] }
|
||||
|
||||
@@ -2,13 +2,15 @@ use crate::utils::date_serializer;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct Device {
|
||||
pub mac_address: String,
|
||||
pub ipv4_address: String,
|
||||
pub vendor: String,
|
||||
#[serde(with = "date_serializer")]
|
||||
#[schema(value_type = String, format = DateTime)]
|
||||
pub last_seen: DateTime<Utc>,
|
||||
pub is_registered: bool,
|
||||
pub owner: String,
|
||||
|
||||
@@ -3,11 +3,13 @@ use chrono::{DateTime, Utc};
|
||||
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{error::Error, fmt, str::FromStr};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct Notification {
|
||||
pub id: i64,
|
||||
#[serde(with = "date_serializer")]
|
||||
#[schema(value_type = String, format = DateTime)]
|
||||
pub created_on: DateTime<Utc>,
|
||||
pub notification_type: NotificationType,
|
||||
pub title: String,
|
||||
@@ -50,7 +52,7 @@ impl PartialEq for Notification {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
|
||||
pub enum NotificationType {
|
||||
NewDeviceFound,
|
||||
DeviceOnlineAfterTime,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::error::Error;
|
||||
|
||||
use crate::model::devices::Device;
|
||||
use crate::model::notifications::{Notification, NotificationType};
|
||||
use crate::settings::get_settings;
|
||||
use crate::web_server::devices::RegisterDevicePayload;
|
||||
use axum::extract::Request;
|
||||
use axum::http::StatusCode;
|
||||
use axum::middleware::Next;
|
||||
@@ -12,11 +15,64 @@ use tower::ServiceBuilder;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
use tower_http::services::ServeDir;
|
||||
use axum::Json;
|
||||
use utoipa::OpenApi;
|
||||
use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};
|
||||
use utoipa::Modify;
|
||||
use utoipa_swagger_ui::SwaggerUi;
|
||||
|
||||
pub mod devices;
|
||||
pub mod notifications;
|
||||
pub mod utils;
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "OOTT API",
|
||||
version = "0.1.0",
|
||||
description = "Network monitoring and alert system API"
|
||||
),
|
||||
paths(
|
||||
test_api,
|
||||
devices::list,
|
||||
devices::read,
|
||||
devices::register,
|
||||
devices::unregister,
|
||||
notifications::list,
|
||||
notifications::read,
|
||||
notifications::read_without_flagging,
|
||||
notifications::mark_as_new,
|
||||
notifications::mark_all_as_old,
|
||||
),
|
||||
components(schemas(
|
||||
Device,
|
||||
Notification,
|
||||
NotificationType,
|
||||
RegisterDevicePayload,
|
||||
)),
|
||||
modifiers(&SecurityAddon),
|
||||
tags(
|
||||
(name = "devices", description = "Device management"),
|
||||
(name = "notifications", description = "Notification management"),
|
||||
)
|
||||
)]
|
||||
struct ApiDoc;
|
||||
|
||||
struct SecurityAddon;
|
||||
|
||||
impl Modify for SecurityAddon {
|
||||
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
||||
let components = openapi.components.get_or_insert_with(Default::default);
|
||||
components.add_security_scheme(
|
||||
"bearer_auth",
|
||||
SecurityScheme::Http(
|
||||
HttpBuilder::new()
|
||||
.scheme(HttpAuthScheme::Bearer)
|
||||
.build(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve() -> Result<(), Box<dyn Error>> {
|
||||
info!("Starting web server");
|
||||
let static_files = ServeDir::new("./web");
|
||||
@@ -52,7 +108,8 @@ pub async fn serve() -> Result<(), Box<dyn Error>> {
|
||||
"/",
|
||||
get(|| async { "Go to /web for the UI or to /api for the better UI." }),
|
||||
)
|
||||
.nest_service("/web", static_files);
|
||||
.nest_service("/web", static_files)
|
||||
.merge(SwaggerUi::new("/api/docs").url("/api/docs/openapi.json", ApiDoc::openapi()));
|
||||
|
||||
let web_server_host_and_port = format!(
|
||||
"{}:{}",
|
||||
@@ -70,6 +127,14 @@ pub async fn serve() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/test",
|
||||
responses(
|
||||
(status = 200, description = "API is reachable", body = String),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
async fn test_api() -> Result<Json<String>, StatusCode> {
|
||||
Ok(Json("OOTT_API_OK".to_string()))
|
||||
}
|
||||
|
||||
@@ -6,11 +6,30 @@ use axum::{Json, extract::Query, http::StatusCode};
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::{debug, error};
|
||||
use serde::Deserialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::{db, model::devices::Device};
|
||||
|
||||
use crate::web_server::utils;
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/devices",
|
||||
tag = "devices",
|
||||
params(
|
||||
("is_registered" = Option<bool>, Query, description = "Filter by registration status"),
|
||||
("last_seen_from" = Option<String>, Query, description = "Filter devices seen after this datetime (RFC3339)"),
|
||||
("last_seen_to" = Option<String>, Query, description = "Filter devices seen before this datetime (RFC3339)"),
|
||||
("owner" = Option<String>, Query, description = "Filter by owner"),
|
||||
("device_type" = Option<String>, Query, description = "Filter by device type"),
|
||||
("vendor" = Option<String>, Query, description = "Filter by vendor"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "List of devices", body = Vec<Device>),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn list(
|
||||
Query(params): Query<HashMap<String, String>>,
|
||||
) -> Result<Json<Vec<Device>>, StatusCode> {
|
||||
@@ -38,6 +57,19 @@ pub async fn list(
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/devices/{mac_address}",
|
||||
tag = "devices",
|
||||
params(
|
||||
("mac_address" = String, Path, description = "MAC address of the device"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Device found", body = Device),
|
||||
(status = 404, description = "Device not found"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn read(Path(mac_address): Path<String>) -> Result<Json<Device>, StatusCode> {
|
||||
match db::devices::read(mac_address) {
|
||||
Some(value) => Ok(Json(value)),
|
||||
@@ -45,6 +77,19 @@ pub async fn read(Path(mac_address): Path<String>) -> Result<Json<Device>, Statu
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
put,
|
||||
path = "/api/devices",
|
||||
tag = "devices",
|
||||
request_body = RegisterDevicePayload,
|
||||
responses(
|
||||
(status = 201, description = "Device registered"),
|
||||
(status = 404, description = "Device not found"),
|
||||
(status = 409, description = "Device already registered"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn register(Json(payload): Json<RegisterDevicePayload>) -> impl IntoResponse {
|
||||
debug!(
|
||||
"Device registration received: mac_address={}, owner={}, device_type={}",
|
||||
@@ -84,6 +129,21 @@ pub async fn register(Json(payload): Json<RegisterDevicePayload>) -> impl IntoRe
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/api/devices/{mac_address}",
|
||||
tag = "devices",
|
||||
params(
|
||||
("mac_address" = String, Path, description = "MAC address of the device"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Device unregistered"),
|
||||
(status = 404, description = "Device not found"),
|
||||
(status = 409, description = "Device is not registered"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn unregister(Path(mac_address): Path<String>) -> impl IntoResponse {
|
||||
let mut device = match db::devices::read(mac_address) {
|
||||
Some(value) => value,
|
||||
@@ -119,7 +179,7 @@ pub async fn unregister(Path(mac_address): Path<String>) -> impl IntoResponse {
|
||||
}
|
||||
|
||||
// Payload structs
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct RegisterDevicePayload {
|
||||
mac_address: String,
|
||||
owner: String,
|
||||
|
||||
@@ -10,6 +10,20 @@ use log::error;
|
||||
|
||||
use crate::{db, model::notifications::Notification, web_server::utils};
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/notifications/{id}",
|
||||
tag = "notifications",
|
||||
params(
|
||||
("id" = i64, Path, description = "Notification ID"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Notification found and marked as read", body = Notification),
|
||||
(status = 404, description = "Notification not found"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn read(Path(id): Path<i64>) -> Result<Json<Notification>, StatusCode> {
|
||||
match db::notifications::mark_as_old(id) {
|
||||
Ok(_) => {}
|
||||
@@ -25,6 +39,19 @@ pub async fn read(Path(id): Path<i64>) -> Result<Json<Notification>, StatusCode>
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/notifications/{id}/read_without_flagging",
|
||||
tag = "notifications",
|
||||
params(
|
||||
("id" = i64, Path, description = "Notification ID"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Notification found without marking as read", body = Notification),
|
||||
(status = 404, description = "Notification not found"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn read_without_flagging(Path(id): Path<i64>) -> Result<Json<Notification>, StatusCode> {
|
||||
match db::notifications::read(id) {
|
||||
Some(value) => Ok(Json(value)),
|
||||
@@ -32,6 +59,19 @@ pub async fn read_without_flagging(Path(id): Path<i64>) -> Result<Json<Notificat
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/notifications/{id}/mark_as_new",
|
||||
tag = "notifications",
|
||||
params(
|
||||
("id" = i64, Path, description = "Notification ID"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Notification marked as new"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn mark_as_new(Path(id): Path<i64>) -> impl IntoResponse {
|
||||
match db::notifications::mark_as_new(id) {
|
||||
Ok(_) => (StatusCode::OK, "Notification marked as new"),
|
||||
@@ -45,6 +85,16 @@ pub async fn mark_as_new(Path(id): Path<i64>) -> impl IntoResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/notifications/mark_all_as_old",
|
||||
tag = "notifications",
|
||||
responses(
|
||||
(status = 200, description = "All notifications marked as old"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn mark_all_as_old() -> impl IntoResponse {
|
||||
match db::notifications::mark_all_as_old() {
|
||||
Ok(_) => (StatusCode::OK, "All notifications marked as old"),
|
||||
@@ -58,6 +108,21 @@ pub async fn mark_all_as_old() -> impl IntoResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/notifications",
|
||||
tag = "notifications",
|
||||
params(
|
||||
("is_new" = Option<bool>, Query, description = "Filter by new/read status"),
|
||||
("page_offset" = Option<i64>, Query, description = "Pagination offset"),
|
||||
("page_limit" = Option<i64>, Query, description = "Maximum number of results to return"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "List of notifications", body = Vec<Notification>),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn list(
|
||||
Query(params): Query<HashMap<String, String>>,
|
||||
) -> Result<Json<Vec<Notification>>, StatusCode> {
|
||||
|
||||
Reference in New Issue
Block a user