headless_lms_server/controllers/main_frontend/
time.rs1use crate::prelude::*;
6use chrono::{SecondsFormat, Utc};
7use utoipa::OpenApi;
8
9#[derive(OpenApi)]
10#[openapi(paths(get_current_time))]
11pub(crate) struct MainFrontendTimeApiDoc;
12
13#[utoipa::path(
20 get,
21 path = "",
22 operation_id = "getCurrentTime",
23 tag = "time",
24 responses(
25 (status = 200, description = "Current server time", body = String)
26 )
27)]
28pub async fn get_current_time() -> ControllerResult<HttpResponse> {
29 let server_time = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);
30 let token = skip_authorize();
31
32 token.authorized_ok(
33 HttpResponse::Ok()
34 .insert_header((
35 "Cache-Control",
36 "no-store, no-cache, must-revalidate, max-age=0",
37 ))
38 .insert_header(("Pragma", "no-cache"))
39 .insert_header(("Expires", "0"))
40 .json(server_time),
41 )
42}
43
44pub fn _add_routes(cfg: &mut ServiceConfig) {
45 cfg.route("", web::get().to(get_current_time));
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use actix_web::{App, test, web};
52
53 #[actix_web::test]
54 async fn returns_non_cacheable_rfc3339_json_string() {
55 let app = test::init_service(App::new().service(web::scope("/api/v0").service(
56 web::scope("/main-frontend").service(web::scope("/time").configure(_add_routes)),
57 )))
58 .await;
59
60 let req = test::TestRequest::with_uri("/api/v0/main-frontend/time").to_request();
61 let resp = test::call_service(&app, req).await;
62
63 assert!(resp.status().is_success());
64 assert_eq!(
65 resp.headers().get("Cache-Control").unwrap(),
66 "no-store, no-cache, must-revalidate, max-age=0"
67 );
68 assert_eq!(resp.headers().get("Pragma").unwrap(), "no-cache");
69 assert_eq!(resp.headers().get("Expires").unwrap(), "0");
70
71 let body: String = test::read_body_json(resp).await;
72 assert!(chrono::DateTime::parse_from_rfc3339(&body).is_ok());
73
74 let parsed = chrono::DateTime::parse_from_rfc3339(&body).unwrap();
75 let server_utc = parsed.with_timezone(&chrono::Utc);
76 let now = chrono::Utc::now();
77 let diff = (server_utc - now).abs();
78 assert!(
79 diff < chrono::Duration::seconds(5),
80 "server time should be close to now"
81 );
82 }
83}