♻️ Major code restructuring
This commit is contained in:
parent
a96e203bb3
commit
fa66d628a0
221 changed files with 228 additions and 315 deletions
193
src/response/page.rs
Normal file
193
src/response/page.rs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
mod error;
|
||||
pub use error::ErrorPage;
|
||||
|
||||
pub use actix_web::Result as ResultPage;
|
||||
|
||||
use crate::base::action;
|
||||
use crate::core::component::{AnyComponents, ArcAnyComponent, ComponentTrait};
|
||||
use crate::core::component::{Context, ContextOp};
|
||||
use crate::core::theme::ComponentsInRegions;
|
||||
use crate::html::{html, Markup, DOCTYPE};
|
||||
use crate::html::{ClassesOp, Favicon, OptionClasses, OptionId, OptionTranslated};
|
||||
use crate::locale::L10n;
|
||||
use crate::{fn_with, service};
|
||||
|
||||
use unic_langid::CharacterDirection;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub struct Page {
|
||||
title : OptionTranslated,
|
||||
description : OptionTranslated,
|
||||
metadata : Vec<(&'static str, &'static str)>,
|
||||
properties : Vec<(&'static str, &'static str)>,
|
||||
favicon : Option<Favicon>,
|
||||
context : Context,
|
||||
body_classes: OptionClasses,
|
||||
skip_to : OptionId,
|
||||
regions : ComponentsInRegions,
|
||||
template : String,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
#[rustfmt::skip]
|
||||
pub fn new(request: service::HttpRequest) -> Self {
|
||||
Page {
|
||||
title : OptionTranslated::default(),
|
||||
description : OptionTranslated::default(),
|
||||
metadata : Vec::default(),
|
||||
properties : Vec::default(),
|
||||
favicon : None,
|
||||
context : Context::new(request),
|
||||
body_classes: OptionClasses::default(),
|
||||
skip_to : OptionId::default(),
|
||||
regions : ComponentsInRegions::default(),
|
||||
template : "default".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
// Page BUILDER.
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_title(&mut self, title: L10n) -> &mut Self {
|
||||
self.title.alter_value(title);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_description(&mut self, description: L10n) -> &mut Self {
|
||||
self.description.alter_value(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_metadata(&mut self, name: &'static str, content: &'static str) -> &mut Self {
|
||||
self.metadata.push((name, content));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_property(&mut self, property: &'static str, content: &'static str) -> &mut Self {
|
||||
self.metadata.push((property, content));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self {
|
||||
self.favicon = favicon;
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_context(&mut self, op: ContextOp) -> &mut Self {
|
||||
self.context.alter(op);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_body_classes(&mut self, op: ClassesOp, classes: impl Into<String>) -> &mut Self {
|
||||
self.body_classes.alter_value(op, classes);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_skip_to(&mut self, id: impl Into<String>) -> &mut Self {
|
||||
self.skip_to.alter_value(id);
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_component_in(
|
||||
&mut self,
|
||||
region: &'static str,
|
||||
component: impl ComponentTrait,
|
||||
) -> &mut Self {
|
||||
self.regions
|
||||
.add_component_in(region, ArcAnyComponent::new(component));
|
||||
self
|
||||
}
|
||||
|
||||
#[fn_with]
|
||||
pub fn alter_template(&mut self, template: &str) -> &mut Self {
|
||||
self.template = template.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
// Page GETTERS.
|
||||
|
||||
pub fn title(&mut self) -> Option<String> {
|
||||
self.title.using(self.context.langid())
|
||||
}
|
||||
|
||||
pub fn description(&mut self) -> Option<String> {
|
||||
self.description.using(self.context.langid())
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> &Vec<(&str, &str)> {
|
||||
&self.metadata
|
||||
}
|
||||
|
||||
pub fn properties(&self) -> &Vec<(&str, &str)> {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
pub fn favicon(&self) -> &Option<Favicon> {
|
||||
&self.favicon
|
||||
}
|
||||
|
||||
pub fn context(&mut self) -> &mut Context {
|
||||
&mut self.context
|
||||
}
|
||||
|
||||
pub fn body_classes(&self) -> &OptionClasses {
|
||||
&self.body_classes
|
||||
}
|
||||
|
||||
pub fn skip_to(&self) -> &OptionId {
|
||||
&self.skip_to
|
||||
}
|
||||
|
||||
pub fn components_in(&self, region: &str) -> AnyComponents {
|
||||
self.regions.get_components(self.context.theme(), region)
|
||||
}
|
||||
|
||||
pub fn template(&self) -> &str {
|
||||
self.template.as_str()
|
||||
}
|
||||
|
||||
// Page RENDER.
|
||||
|
||||
pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> {
|
||||
// Theme actions before preparing the page body.
|
||||
self.context.theme().before_prepare_body(self);
|
||||
|
||||
// Packages actions before preparing the page body.
|
||||
action::page::BeforePrepareBody::dispatch(self);
|
||||
|
||||
// Prepare page body.
|
||||
let body = self.context.theme().prepare_body(self);
|
||||
|
||||
// Theme actions after preparing the page body.
|
||||
self.context.theme().after_prepare_body(self);
|
||||
|
||||
// Packages actions after preparing the page body.
|
||||
action::page::AfterPrepareBody::dispatch(self);
|
||||
|
||||
// Prepare page head.
|
||||
let head = self.context.theme().prepare_head(self);
|
||||
|
||||
// Render the page.
|
||||
let lang = self.context.langid().language.as_str();
|
||||
let dir = match self.context.langid().character_direction() {
|
||||
CharacterDirection::LTR => "ltr",
|
||||
CharacterDirection::RTL => "rtl",
|
||||
CharacterDirection::TTB => "auto",
|
||||
};
|
||||
Ok(html! {
|
||||
(DOCTYPE)
|
||||
html lang=(lang) dir=(dir) {
|
||||
(head)
|
||||
(body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
86
src/response/page/error.rs
Normal file
86
src/response/page/error.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use crate::base::component::{Error403, Error404};
|
||||
use crate::locale::L10n;
|
||||
use crate::response::ResponseError;
|
||||
use crate::service::http::{header::ContentType, StatusCode};
|
||||
use crate::service::{HttpRequest, HttpResponse};
|
||||
|
||||
use super::Page;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ErrorPage {
|
||||
NotModified(HttpRequest),
|
||||
BadRequest(HttpRequest),
|
||||
AccessDenied(HttpRequest),
|
||||
NotFound(HttpRequest),
|
||||
PreconditionFailed(HttpRequest),
|
||||
InternalError(HttpRequest),
|
||||
Timeout(HttpRequest),
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorPage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
// Error 304.
|
||||
ErrorPage::NotModified(_) => write!(f, "Not Modified"),
|
||||
// Error 400.
|
||||
ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"),
|
||||
// Error 403.
|
||||
ErrorPage::AccessDenied(request) => {
|
||||
let error_page = Page::new(request.clone());
|
||||
if let Ok(page) = error_page
|
||||
.with_title(L10n::n("Error FORBIDDEN"))
|
||||
.with_component_in("content", Error403)
|
||||
.with_template("error")
|
||||
.render()
|
||||
{
|
||||
write!(f, "{}", page.into_string())
|
||||
} else {
|
||||
write!(f, "Access Denied")
|
||||
}
|
||||
}
|
||||
// Error 404.
|
||||
ErrorPage::NotFound(request) => {
|
||||
let error_page = Page::new(request.clone());
|
||||
if let Ok(page) = error_page
|
||||
.with_title(L10n::n("Error RESOURCE NOT FOUND"))
|
||||
.with_component_in("content", Error404)
|
||||
.with_template("error")
|
||||
.render()
|
||||
{
|
||||
write!(f, "{}", page.into_string())
|
||||
} else {
|
||||
write!(f, "Not Found")
|
||||
}
|
||||
}
|
||||
// Error 412.
|
||||
ErrorPage::PreconditionFailed(_) => write!(f, "Precondition Failed"),
|
||||
// Error 500.
|
||||
ErrorPage::InternalError(_) => write!(f, "Internal Error"),
|
||||
// Error 504.
|
||||
ErrorPage::Timeout(_) => write!(f, "Timeout"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for ErrorPage {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(self.status_code())
|
||||
.insert_header(ContentType::html())
|
||||
.body(self.to_string())
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
ErrorPage::NotModified(_) => StatusCode::NOT_MODIFIED,
|
||||
ErrorPage::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||
ErrorPage::AccessDenied(_) => StatusCode::FORBIDDEN,
|
||||
ErrorPage::NotFound(_) => StatusCode::NOT_FOUND,
|
||||
ErrorPage::PreconditionFailed(_) => StatusCode::PRECONDITION_FAILED,
|
||||
ErrorPage::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ErrorPage::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/response/redirect.rs
Normal file
76
src/response/redirect.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//! Perform redirections in HTTP.
|
||||
//!
|
||||
//! **URL redirection**, also known as *URL forwarding*, is a technique to give more than one URL
|
||||
//! address to a web resource. HTTP has a response called ***HTTP redirect*** for this operation
|
||||
//! (see [Redirections in HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections)).
|
||||
//!
|
||||
//! There are several types of redirects, sorted into three categories:
|
||||
//!
|
||||
//! * **Permanent redirections**. These redirections are meant to last forever. They imply that
|
||||
//! the original URL should no longer be used, and replaced with the new one. Search engine
|
||||
//! robots, RSS readers, and other crawlers will update the original URL for the resource.
|
||||
//!
|
||||
//! * **Temporary redirections**. Sometimes the requested resource can't be accessed from its
|
||||
//! canonical location, but it can be accessed from another place. In this case, a temporary
|
||||
//! redirect can be used. Search engine robots and other crawlers don't memorize the new,
|
||||
//! temporary URL. Temporary redirections are also used when creating, updating, or deleting
|
||||
//! resources, to show temporary progress pages.
|
||||
//!
|
||||
//! * **Special redirections**.
|
||||
|
||||
use crate::service::HttpResponse;
|
||||
|
||||
pub struct Redirect;
|
||||
|
||||
impl Redirect {
|
||||
/// Permanent redirection. Status Code **301**. GET methods unchanged. Others may or may not be
|
||||
/// changed to GET. Typical for reorganization of a website.
|
||||
pub fn moved(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::MovedPermanently()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Permanent redirection. Status Code **308**. Method and body not changed. Typical for
|
||||
/// reorganization of a website, with non-GET links/operations.
|
||||
pub fn permanent(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::PermanentRedirect()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Temporary redirection. Status Code **302**. GET methods unchanged. Others may or may not be
|
||||
/// changed to GET. Used when the web page is temporarily unavailable for unforeseen reasons.
|
||||
pub fn found(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::Found()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Temporary redirection. Status Code **303**. GET methods unchanged. Others changed to GET
|
||||
/// (body lost). Used to redirect after a PUT or a POST, so that refreshing the result page
|
||||
/// doesn't re-trigger the operation.
|
||||
pub fn see_other(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::SeeOther()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Temporary redirection. Status Code **307**. Method and body not changed. The web page is
|
||||
/// temporarily unavailable for unforeseen reasons. Better than [`found()`](Self::found) when
|
||||
/// non-GET operations are available on the site.
|
||||
pub fn temporary(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::TemporaryRedirect()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Special redirection. Status Code **304**. Redirects a page to the locally cached copy (that
|
||||
/// was stale). Sent for revalidated conditional requests. Indicates that the cached response is
|
||||
/// still fresh and can be used.
|
||||
pub fn not_modified(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::NotModified()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue