lexa_framework/http/
context.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ Copyright: (c) 2023, Mike 'PhiSyX' S. (https://github.com/PhiSyX)         ┃
3// ┃ SPDX-License-Identifier: MPL-2.0                                          ┃
4// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
5// ┃                                                                           ┃
6// ┃  This Source Code Form is subject to the terms of the Mozilla Public      ┃
7// ┃  License, v. 2.0. If a copy of the MPL was not distributed with this      ┃
8// ┃  file, You can obtain one at https://mozilla.org/MPL/2.0/.                ┃
9// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
10
11use std::ops;
12use std::sync::Arc;
13
14use super::{HttpRequest, HttpResponse};
15
16// --------- //
17// Interface //
18// --------- //
19
20#[async_trait::async_trait]
21pub trait HttpContextInterface: Send + Sync {
22	type State;
23
24	async fn new(
25		extensions: &super::Extensions,
26		state: Self::State,
27	) -> Option<Self>
28	where
29		Self: Sized;
30
31	fn shared(self) -> Arc<Self>
32	where
33		Self: Sized,
34	{
35		Arc::new(self)
36	}
37}
38
39// --------- //
40// Structure //
41// --------- //
42
43pub struct HttpContext<T> {
44	pub(crate) context: Arc<T>,
45	pub request: HttpRequest<T>,
46	pub response: HttpResponse<T>,
47	#[cfg(feature = "cookies")]
48	pub cookies: super::cookies::Cookies,
49	#[cfg(feature = "cookies")]
50	pub session: super::session::Session,
51}
52
53// -------------- //
54// Implémentation //
55// -------------- //
56
57impl<T> HttpContext<T> {
58	/// Redirige le client sur l'URL précédente. (Se basant sur l'en-tête HTTP
59	/// `Referer`).
60	pub fn redirect_back(&self) -> axum::response::Redirect {
61		assert!(self.request.referer.is_some());
62		let referer = self.request.referer.as_ref().expect("Referer");
63
64		fn referer_url(referer: &axum::headers::Referer) -> String {
65			let referer_s = format!("{referer:?}");
66
67			let trimmed_referer = referer_s
68				.trim_start_matches("Referer(\"")
69				.trim_end_matches("\")");
70
71			trimmed_referer.to_owned()
72		}
73
74		let uri = referer_url(referer);
75
76		self.response.redirect_to(uri)
77	}
78}
79
80#[cfg(feature = "auth")]
81impl<T> HttpContext<T> {
82	/// Déconnecte l'utilisateur de la session, et détruit le cookie de
83	/// connexion associé à l'utilisateur.
84	pub async fn logout_user(&mut self) {
85		let mut session = self.session.write().await;
86		session.remove(crate::auth::AUTH_USER_ID_SESSION);
87		session.remove(crate::auth::AUTH_ADMIN_ID_SESSION);
88		session.regenerate();
89
90		if let Some(mut user_cookie) = self
91			.cookies
92			.private()
93			.get(crate::auth::AUTH_USER_ID_SESSION)
94		{
95			let expires_in = time::OffsetDateTime::now_utc()
96				.checked_sub(time::Duration::days(100));
97			user_cookie.set_path("/");
98			user_cookie.set_expires(expires_in);
99			self.cookies.private().add(user_cookie);
100		}
101
102		if let Some(mut adm_cookie) = self
103			.cookies
104			.private()
105			.get(crate::auth::AUTH_ADMIN_ID_SESSION)
106		{
107			let expires_in = time::OffsetDateTime::now_utc()
108				.checked_sub(time::Duration::days(100));
109			adm_cookie.set_path("/");
110			adm_cookie.set_expires(expires_in);
111			self.cookies.private().add(adm_cookie);
112		}
113	}
114}
115
116// -------------- //
117// Implémentation // -> Interface
118// -------------- //
119
120impl<T> ops::Deref for HttpContext<T> {
121	type Target = Arc<T>;
122
123	fn deref(&self) -> &Self::Target {
124		&self.context
125	}
126}