zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use lazy_static::lazy_static;

use std::env;
use std::sync::{Arc, RwLock};

use actix_web::HttpMessage;
use actix_web::{HttpRequest, HttpResponse};

use serde::Serialize;
use tera::{Context as TeraContext, Tera};

use crate::commons::read_env;
use crate::core::auth0;
use crate::core::buildinfo;

use crate::core::error2::Result;
use crate::core::error2::{self};

lazy_static! {
    static ref BUILD_TIME: String = buildinfo::timestamp();
    static ref BUILD_VERSION: String = buildinfo::git_version();
    static ref START_UPTIME: String = read_env("STARTUP_TIME", &buildinfo::timestamp());
    static ref ENV_NAME: String = read_env("ENV_NAME", "LOCAL");
    static ref APP_NAME: String = read_env("APP_NAME", "APP_NAME_UNSET");
    static ref GRAPHQL_SERVER: String = read_env("RS_ENV_GRAPHQL_SERVER", "");
    static ref STATIC_SERVER: String = read_env("RS_ENV_STATIC_SERVER", "");
}

/// A trait for making certain types of response handling easier.
pub trait Render {
    /// Shorthand for rendering a template, with a specific HTTP response code.
    fn render(&self, code: usize, template: &str, context: TeraContext) -> Result<HttpResponse>;

    /// Shorthand for returning a JSON payload.
    fn json<S: Serialize>(&self, code: usize, payload: S) -> Result<HttpResponse>;

    /// Shorthand for returning a text/plain payload.
    fn text(&self, code: usize, payload: &str) -> Result<HttpResponse>;

    /// Handy redirects helper.
    fn redirect(&self, location: &str) -> Result<HttpResponse>;
}

impl Render for HttpRequest {
    fn render(
        &self,
        code: usize,
        template: &str,
        mut context: TeraContext,
    ) -> Result<HttpResponse> {
        let _tera: Option<&Arc<RwLock<Tera>>> = self.app_data();

        context.insert("BUILD_TIME", &*BUILD_TIME);
        context.insert("BUILD_VERSION", &*BUILD_VERSION);
        context.insert("STARTUP_TIME", &*START_UPTIME);

        context.insert("APP_NAME", &*APP_NAME);
        context.insert("ENV_NAME", &*ENV_NAME);
        context.insert("REQUEST_URI", self.path());

        context.insert("GRAPHQL_SERVER", &*GRAPHQL_SERVER);
        context.insert("STATIC_SERVER", &*STATIC_SERVER);

        for (k, v) in env::vars() {
            if k.starts_with("JELLY_") {
                context.insert(&k, &v);
            }
        }

        if let Some(requestor) = self.extensions().get::<auth0::Requestor>() {
            if let Some(user_details) = requestor.get_user() {
                context.insert("USER_ID", &user_details.user_id());
                context.insert("USER_NAME", &user_details.user_name);
                context.insert("USER_INFO", &auth0::UserInfo::build(user_details));
                context.insert("IS_AUTHENTICATED", &true);
            }
        }

        let _query_string = self.query_string();

        if let Some(eng) = _tera {
            let engine = eng
                .read()
                .map_err(|e| error2::Error::throw("Error acquiring template read lock", Some(e)))?;

            //
            let body = match engine.render(template, &context) {
                Ok(body) => body,
                Err(e) => {
                    return Err(error2::Error::throw(
                        "Unable to locate Templates cache",
                        Some(e),
                    ));
                }
            };

            Ok(match code {
                200 | 400 | 404 => HttpResponse::Ok(),
                _ => HttpResponse::Ok(),
            }
            .content_type("text/html; charset=utf-8")
            .body(body))
        } else {
            Err(error2::Error::throw(
                "Unable to locate Templates cache",
                Some(""),
            ))
        }
    }

    fn json<S: Serialize>(&self, code: usize, payload: S) -> Result<HttpResponse> {
        let o = serde_json::to_string(&payload).map_err(|e| error2::Error::throw("", Some(e)))?;

        Ok(match code {
            404 => HttpResponse::NotFound(),
            400 => HttpResponse::Ok(),
            _ => HttpResponse::Ok(),
        }
        .content_type("application/json")
        .body(o))
    }

    fn text(&self, code: usize, payload: &str) -> Result<HttpResponse> {
        Ok(match code {
            404 => HttpResponse::NotFound(),
            400 => HttpResponse::Ok(),
            _ => HttpResponse::Ok(),
        }
        .content_type("text/plain")
        .body(payload.to_string()))
    }

    fn redirect(&self, location: &str) -> Result<HttpResponse> {
        Ok(HttpResponse::Found()
            .append_header((actix_web::http::header::LOCATION, location))
            .finish())
    }
}