-
Pierre Jarriges authoredPierre Jarriges authored
view_resource.rs 6.09 KiB
use crate::{
middleware::AuthenticatedAdminMiddleware,
model::AdminAuthCredentials,
// view_resource::{ViewResource, ViewResourceDescriptor},
AppState,
};
use actix_web::{web::Form, HttpMessage, HttpRequest, HttpResponse};
use std::{env::var as env_var, fs::read_to_string as file_to_string, path::PathBuf};
#[derive(Debug, Clone)]
/// Loads a static resource data allowing it to be served by the get_view service.
/// It holds a name, allowing the resource to be retrived by name,
/// a content which can be any text content stored in a string (like an html document),
/// a path to the directory of the actual static resource, and a boolean which indicates wether
/// or not an authentication verification should be applied.
pub struct ViewResource {
pub name: String,
pub string_contents: String,
pub dir_path: PathBuf,
pub apply_auth_middleware: bool,
}
#[derive(Debug, Clone)]
/// Defines the values that will be used to construct a ViewResource.
/// It must be passed to the AppViewResourceManager for resource registration
pub struct ViewResourceDescriptor<'a> {
pub path_str: &'a str,
pub index_file_name: &'a str,
pub resource_name: &'a str,
pub apply_auth_middleware: bool,
}
#[derive(Debug, Clone)]
/// A structure reponsible of registering and retrieving static resources.
pub struct ViewResourceManager {
resources: Vec<ViewResource>,
}
impl ViewResourceManager {
pub fn new() -> Self {
ViewResourceManager { resources: vec![] }
}
/// Calls the constructor and registers the resources described as argument before returning the instance
pub fn with_views(resource_descriptors: Vec<ViewResourceDescriptor>) -> Self {
let mut instance = Self::new();
instance.register_batch(resource_descriptors);
instance
}
/// Registers a new static resource in the instance.
/// The path provided in the argument must point to an existing file
pub fn register(&mut self, desc: ViewResourceDescriptor) {
let static_dir = std::path::PathBuf::from(
env_var("RESOURCES_DIR").expect("RESOURCES_DIR is not defined"),
)
.join("public/views");
let dir_path = static_dir.join(desc.path_str);
let path: PathBuf = format!("{}/{}", dir_path.to_str().unwrap(), desc.index_file_name)
.parse()
.expect(&format!(
"Failed to pare resource index file path {:?}",
desc.index_file_name
));
let string_contents = file_to_string(path).unwrap();
&self.resources.push(ViewResource {
name: desc.resource_name.to_string(),
dir_path,
string_contents,
apply_auth_middleware: desc.apply_auth_middleware,
});
}
/// Registers a collection of multiple resources.
pub fn register_batch(&mut self, resource_descriptors: Vec<ViewResourceDescriptor>) {
for desc in resource_descriptors.iter() {
self.register(desc.clone());
}
}
/// Retrieves a resource by name and returns a reference to it or None.
pub fn get_resource(&self, name: &str) -> Option<&ViewResource> {
self.resources.iter().find(|res| res.name == name)
}
/// Retrieves a resource by name and returns it as an http response.
/// This can be returned as it by a service.
pub async fn get_resource_as_http_response<'a>(
&self,
app_state: &AppState,
auth_middleware: &AuthenticatedAdminMiddleware<'a>,
req: &HttpRequest,
auth_data: Option<Form<AdminAuthCredentials>>,
resource_name: &str,
) -> HttpResponse {
match self.get_resource(resource_name) {
Some(res) => {
if res.apply_auth_middleware {
let auth_cookie = auth_middleware.exec(app_state, req, auth_data).await;
if auth_cookie.is_err() {
let unauthorized_view = match self.get_resource("unauthorized") {
Some(res_404) => res_404.string_contents.to_string(),
None => {
println!("WARNING: missing Unauthorized view resource");
"
<h1>Unauthorized</h1>
<p>You must login as an administrator to access this page</p>
<a href='/v/admin-login'>Login page</a>
"
.to_string()
}
};
let mut response_builder = HttpResponse::Unauthorized();
return match req.cookie(auth_middleware.cookie_name) {
Some(cookie) => {
// Invalidate auth_cookie if auth failed in any way
response_builder
.del_cookie(&cookie)
.content_type("text/html")
.body(unauthorized_view)
}
None => response_builder
.content_type("text/html")
.body(unauthorized_view),
};
} else {
return HttpResponse::Ok()
.content_type("text/html")
.cookie(auth_cookie.unwrap())
.body(&res.string_contents);
}
}
HttpResponse::Ok()
.content_type("text/html")
.body(&res.string_contents)
}
None => match self.get_resource("404") {
Some(res_404) => HttpResponse::NotFound()
.content_type("text/html")
.body(&res_404.string_contents),
None => {
println!("WARNING: missing 404 view resource");
HttpResponse::NotFound().finish()
}
},
}
}
}