1use axum::Json;
2use axum::extract::Query;
3use axum::http::StatusCode;
4use axum::http::request::Parts;
5use headers::authorization::Bearer;
6use headers::{Authorization, HeaderMapExt};
7use serde::de::DeserializeOwned;
8#[cfg(feature = "with-ulid")]
9use ulid::Ulid;
10
11use fusion_common::ctx::Ctx;
12use fusion_common::model::IdI64Result;
13use fusion_common::time::now_offset;
14use fusion_core::configuration::SecuritySetting;
15use fusion_core::log::get_trace_id;
16use fusion_core::security::{AccessToken, SecurityUtils};
17
18use crate::WebResult;
19use crate::error::WebError;
20
21#[macro_export]
23macro_rules! ok_json {
24 () => {
25 Ok(axum::Json(().into()))
26 };
27 ($v:expr) => {
28 Ok(axum::Json($v))
29 };
30}
31
32#[inline]
33pub fn ok_id(id: i64) -> WebResult<IdI64Result> {
34 Ok(IdI64Result::new(id).into())
35}
36
37#[cfg(feature = "with-ulid")]
38#[inline]
39pub fn ok_ulid(id: Ulid) -> WebResult<fusion_common::model::IdUlidResult> {
40 Ok(fusion_common::model::IdUlidResult::new(id).into())
41}
42
43#[cfg(feature = "with-uuid")]
44#[inline]
45pub fn ok_uuid(id: uuid::Uuid) -> WebResult<fusion_common::model::IdUuidResult> {
46 Ok(fusion_common::model::IdUuidResult::new(id).into())
47}
48
49pub fn unauthorized_app_error(msg: impl Into<String>) -> (StatusCode, Json<WebError>) {
50 (StatusCode::UNAUTHORIZED, Json(WebError::new_with_msg(msg).with_err_code(401)))
51}
52
53pub fn extract_ctx(parts: &Parts, sc: &SecuritySetting) -> Result<Ctx, WebError> {
55 let req_time = now_offset();
56
57 let token = if let Some(Authorization(bearer)) = parts.headers.typed_get::<Authorization<Bearer>>() {
58 bearer.token().to_string()
59 } else if let Ok(at) = Query::<AccessToken>::try_from_uri(&parts.uri) {
60 at.0.access_token
61 } else {
62 return Err(WebError::new_with_code(401, "Missing token"));
63 };
64
65 let (payload, _) =
66 SecurityUtils::decrypt_jwt(sc.pwd(), &token).map_err(|_e| WebError::new_with_code(401, "Failed decode jwt"))?;
67
68 let ctx =
69 Ctx::try_new(payload, Some(req_time), get_trace_id()).map_err(|e| WebError::new_with_code(401, e.to_string()))?;
70 Ok(ctx)
71}
72
73pub fn opt_to_app_result<T>(opt: Option<T>) -> WebResult<T>
74where
75 T: DeserializeOwned,
76{
77 if let Some(v) = opt { Ok(Json(v)) } else { Err(WebError::new_with_code(404, "Not found.")) }
78}