mas_handlers/admin/v1/oauth2_sessions/
get.rs1use aide::{OperationIo, transform::TransformOperation};
8use axum::{Json, response::IntoResponse};
9use hyper::StatusCode;
10use ulid::Ulid;
11
12use crate::{
13 admin::{
14 call_context::CallContext,
15 model::OAuth2Session,
16 params::UlidPathParam,
17 response::{ErrorResponse, SingleResponse},
18 },
19 impl_from_error_for_route,
20};
21
22#[derive(Debug, thiserror::Error, OperationIo)]
23#[aide(output_with = "Json<ErrorResponse>")]
24pub enum RouteError {
25 #[error(transparent)]
26 Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
27
28 #[error("OAuth 2.0 session ID {0} not found")]
29 NotFound(Ulid),
30}
31
32impl_from_error_for_route!(mas_storage::RepositoryError);
33
34impl IntoResponse for RouteError {
35 fn into_response(self) -> axum::response::Response {
36 let error = ErrorResponse::from_error(&self);
37 let status = match self {
38 Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
39 Self::NotFound(_) => StatusCode::NOT_FOUND,
40 };
41 (status, Json(error)).into_response()
42 }
43}
44
45pub fn doc(operation: TransformOperation) -> TransformOperation {
46 operation
47 .id("getOAuth2Session")
48 .summary("Get an OAuth 2.0 session")
49 .tag("oauth2-session")
50 .response_with::<200, Json<SingleResponse<OAuth2Session>>, _>(|t| {
51 let [sample, ..] = OAuth2Session::samples();
52 let response = SingleResponse::new_canonical(sample);
53 t.description("OAuth 2.0 session was found")
54 .example(response)
55 })
56 .response_with::<404, RouteError, _>(|t| {
57 let response = ErrorResponse::from_error(&RouteError::NotFound(Ulid::nil()));
58 t.description("OAuth 2.0 session was not found")
59 .example(response)
60 })
61}
62
63#[tracing::instrument(name = "handler.admin.v1.oauth2_session.get", skip_all, err)]
64pub async fn handler(
65 CallContext { mut repo, .. }: CallContext,
66 id: UlidPathParam,
67) -> Result<Json<SingleResponse<OAuth2Session>>, RouteError> {
68 let session = repo
69 .oauth2_session()
70 .lookup(*id)
71 .await?
72 .ok_or(RouteError::NotFound(*id))?;
73
74 Ok(Json(SingleResponse::new_canonical(OAuth2Session::from(
75 session,
76 ))))
77}
78
79#[cfg(test)]
80mod tests {
81 use hyper::{Request, StatusCode};
82 use mas_data_model::AccessToken;
83 use sqlx::PgPool;
84 use ulid::Ulid;
85
86 use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup};
87
88 #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
89 async fn test_get(pool: PgPool) {
90 setup();
91 let mut state = TestState::from_pool(pool).await.unwrap();
92 let token = state.token_with_scope("urn:mas:admin").await;
93
94 let mut repo = state.repository().await.unwrap();
96 let AccessToken { session_id, .. } = repo
97 .oauth2_access_token()
98 .find_by_token(&token)
99 .await
100 .unwrap()
101 .unwrap();
102 repo.save().await.unwrap();
103
104 let request = Request::get(format!("/api/admin/v1/oauth2-sessions/{session_id}"))
105 .bearer(&token)
106 .empty();
107 let response = state.request(request).await;
108 response.assert_status(StatusCode::OK);
109 let body: serde_json::Value = response.json();
110 assert_eq!(body["data"]["type"], "oauth2-session");
111 insta::assert_json_snapshot!(body, @r###"
112 {
113 "data": {
114 "type": "oauth2-session",
115 "id": "01FSHN9AG0MKGTBNZ16RDR3PVY",
116 "attributes": {
117 "created_at": "2022-01-16T14:40:00Z",
118 "finished_at": null,
119 "user_id": null,
120 "user_session_id": null,
121 "client_id": "01FSHN9AG0FAQ50MT1E9FFRPZR",
122 "scope": "urn:mas:admin",
123 "user_agent": null,
124 "last_active_at": null,
125 "last_active_ip": null
126 },
127 "links": {
128 "self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY"
129 }
130 },
131 "links": {
132 "self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY"
133 }
134 }
135 "###);
136 }
137
138 #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
139 async fn test_not_found(pool: PgPool) {
140 setup();
141 let mut state = TestState::from_pool(pool).await.unwrap();
142 let token = state.token_with_scope("urn:mas:admin").await;
143
144 let session_id = Ulid::nil();
145 let request = Request::get(format!("/api/admin/v1/oauth2-sessions/{session_id}"))
146 .bearer(&token)
147 .empty();
148 let response = state.request(request).await;
149 response.assert_status(StatusCode::NOT_FOUND);
150 }
151}