Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
view_resource.rs 6.09 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pierre Jarriges's avatar
    Pierre Jarriges committed
    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()
                    }
                },
            }
        }
    }