You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
Simplify template render check logic
Also documents a bunch of things in mas_core::templates
This commit is contained in:
@@ -59,7 +59,8 @@ impl TemplatesCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SC::Check { path, skip_builtin } => {
|
SC::Check { path, skip_builtin } => {
|
||||||
Templates::load(Some(path), !skip_builtin)?;
|
let templates = Templates::load(Some(path), !skip_builtin)?;
|
||||||
|
templates.check_render()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ use crate::{errors::ErroredForm, filters::CsrfToken, storage::SessionInfo};
|
|||||||
|
|
||||||
/// Helper trait to construct context wrappers
|
/// Helper trait to construct context wrappers
|
||||||
pub trait TemplateContext {
|
pub trait TemplateContext {
|
||||||
|
/// Attach a user session to the template context
|
||||||
fn with_session(self, current_session: SessionInfo) -> WithSession<Self>
|
fn with_session(self, current_session: SessionInfo) -> WithSession<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -32,6 +33,7 @@ pub trait TemplateContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attach an optional user session to the template context
|
||||||
fn maybe_with_session(self, current_session: Option<SessionInfo>) -> WithOptionalSession<Self>
|
fn maybe_with_session(self, current_session: Option<SessionInfo>) -> WithOptionalSession<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -42,6 +44,7 @@ pub trait TemplateContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attach a CSRF token to the template context
|
||||||
fn with_csrf(self, token: &CsrfToken) -> WithCsrf<Self>
|
fn with_csrf(self, token: &CsrfToken) -> WithCsrf<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -52,6 +55,10 @@ pub trait TemplateContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate sample values for this context type
|
||||||
|
///
|
||||||
|
/// This is then used to check for template validity in unit tests and in
|
||||||
|
/// the CLI (`cargo run -- templates check`)
|
||||||
fn sample() -> Vec<Self>
|
fn sample() -> Vec<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
@@ -32,10 +32,6 @@ macro_rules! register_templates {
|
|||||||
extra = { $( $extra_template:expr ),* };
|
extra = { $( $extra_template:expr ),* };
|
||||||
)?
|
)?
|
||||||
|
|
||||||
$(
|
|
||||||
generics = { $( $generic:ident = $sample:ty ),* };
|
|
||||||
)?
|
|
||||||
|
|
||||||
$(
|
$(
|
||||||
// Match any attribute on the function, such as #[doc], #[allow(dead_code)], etc.
|
// Match any attribute on the function, such as #[doc], #[allow(dead_code)], etc.
|
||||||
$( #[ $attr:meta ] )*
|
$( #[ $attr:meta ] )*
|
||||||
@@ -76,34 +72,31 @@ macro_rules! register_templates {
|
|||||||
.map_err(|source| TemplateError::Render { template: $template, source })
|
.map_err(|source| TemplateError::Render { template: $template, source })
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
pub fn check_render(&self) -> Result<(), TemplateError> {
|
|
||||||
self.check_render_inner $( ::< $( $sample ),+ > )? ()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_render_inner
|
/// Helps rendering each template with sample data
|
||||||
$( < $( $generic ),+ > )?
|
pub mod check {
|
||||||
(&self) -> Result<(), TemplateError>
|
use super::*;
|
||||||
$( where
|
|
||||||
$( $generic : TemplateContext + Serialize, )+
|
|
||||||
)?
|
|
||||||
|
|
||||||
{
|
|
||||||
$(
|
$(
|
||||||
{
|
#[doc = concat!("Render the `", $template, "` template with sample contexts")]
|
||||||
|
pub fn $name
|
||||||
|
$(< $( $lt $( : $clt $(+ $dlt )* + TemplateContext )? ),+ >)?
|
||||||
|
(templates: &Templates)
|
||||||
|
-> anyhow::Result<()> {
|
||||||
let samples: Vec< $param > = TemplateContext::sample();
|
let samples: Vec< $param > = TemplateContext::sample();
|
||||||
|
|
||||||
let name = $template;
|
let name = $template;
|
||||||
for sample in samples {
|
for sample in samples {
|
||||||
::tracing::info!(name, "Rendering template");
|
let context = serde_json::to_value(&sample)?;
|
||||||
self. $name (&sample)?;
|
::tracing::info!(name, %context, "Rendering template");
|
||||||
|
templates. $name (&sample)
|
||||||
|
.with_context(|| format!("Failed to render template {:?} with context {}", name, context))?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)*
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
//! Templates rendering
|
//! Templates rendering
|
||||||
|
|
||||||
use std::{collections::HashSet, io::Cursor, path::Path, string::ToString, sync::Arc};
|
use std::{collections::HashSet, io::Cursor, path::Path, string::ToString, sync::Arc};
|
||||||
@@ -25,7 +27,9 @@ use tokio::{fs::OpenOptions, io::AsyncWriteExt};
|
|||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
use warp::reject::Reject;
|
use warp::reject::Reject;
|
||||||
|
|
||||||
|
#[allow(missing_docs)] // TODO
|
||||||
mod context;
|
mod context;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
@@ -38,14 +42,19 @@ pub use self::context::{
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Templates(Arc<Tera>);
|
pub struct Templates(Arc<Tera>);
|
||||||
|
|
||||||
|
/// There was an issue while loading the templates
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TemplateLoadingError {
|
pub enum TemplateLoadingError {
|
||||||
|
/// Some templates failed to compile
|
||||||
#[error("could not load and compile some templates")]
|
#[error("could not load and compile some templates")]
|
||||||
Compile(#[from] TeraError),
|
Compile(#[from] TeraError),
|
||||||
|
|
||||||
|
/// There are essential templates missing
|
||||||
#[error("missing templates {missing:?}")]
|
#[error("missing templates {missing:?}")]
|
||||||
MissingTemplates {
|
MissingTemplates {
|
||||||
|
/// List of missing templates
|
||||||
missing: HashSet<String>,
|
missing: HashSet<String>,
|
||||||
|
/// List of templates that were loaded
|
||||||
loaded: HashSet<String>,
|
loaded: HashSet<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -146,18 +155,27 @@ impl Templates {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Failed to render a template
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TemplateError {
|
pub enum TemplateError {
|
||||||
|
/// Failed to prepare the context used by this template
|
||||||
#[error("could not prepare context for template {template:?}")]
|
#[error("could not prepare context for template {template:?}")]
|
||||||
Context {
|
Context {
|
||||||
|
/// The name of the template being rendered
|
||||||
template: &'static str,
|
template: &'static str,
|
||||||
|
|
||||||
|
/// The underlying error
|
||||||
#[source]
|
#[source]
|
||||||
source: TeraError,
|
source: TeraError,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Failed to render the template
|
||||||
#[error("could not render template {template:?}")]
|
#[error("could not render template {template:?}")]
|
||||||
Render {
|
Render {
|
||||||
|
/// The name of the template being rendered
|
||||||
template: &'static str,
|
template: &'static str,
|
||||||
|
|
||||||
|
/// The underlying error
|
||||||
#[source]
|
#[source]
|
||||||
source: TeraError,
|
source: TeraError,
|
||||||
},
|
},
|
||||||
@@ -167,7 +185,6 @@ impl Reject for TemplateError {}
|
|||||||
|
|
||||||
register_templates! {
|
register_templates! {
|
||||||
extra = { "base.html" };
|
extra = { "base.html" };
|
||||||
generics = { T = EmptyContext };
|
|
||||||
|
|
||||||
/// Render the login page
|
/// Render the login page
|
||||||
pub fn render_login(WithCsrf<LoginContext>) { "login.html" }
|
pub fn render_login(WithCsrf<LoginContext>) { "login.html" }
|
||||||
@@ -188,12 +205,26 @@ register_templates! {
|
|||||||
pub fn render_error(ErrorContext) { "error.html" }
|
pub fn render_error(ErrorContext) { "error.html" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Templates {
|
||||||
|
/// Render all templates with the generated samples to check if they render
|
||||||
|
/// properly
|
||||||
|
pub fn check_render(&self) -> anyhow::Result<()> {
|
||||||
|
check::render_login(self)?;
|
||||||
|
check::render_register(self)?;
|
||||||
|
check::render_index(self)?;
|
||||||
|
check::render_reauth(self)?;
|
||||||
|
check::render_form_post::<EmptyContext>(self)?;
|
||||||
|
check::render_error(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_all_templates() {
|
fn check_builtin_templates() {
|
||||||
let templates = Templates::load(None, true).unwrap();
|
let templates = Templates::load(None, true).unwrap();
|
||||||
templates.check_render().unwrap();
|
templates.check_render().unwrap();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user