You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +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 } => {
|
||||
Templates::load(Some(path), !skip_builtin)?;
|
||||
let templates = Templates::load(Some(path), !skip_builtin)?;
|
||||
templates.check_render()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use crate::{errors::ErroredForm, filters::CsrfToken, storage::SessionInfo};
|
||||
|
||||
/// Helper trait to construct context wrappers
|
||||
pub trait TemplateContext {
|
||||
/// Attach a user session to the template context
|
||||
fn with_session(self, current_session: SessionInfo) -> WithSession<Self>
|
||||
where
|
||||
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>
|
||||
where
|
||||
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>
|
||||
where
|
||||
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>
|
||||
where
|
||||
Self: Sized;
|
||||
|
@ -32,10 +32,6 @@ macro_rules! register_templates {
|
||||
extra = { $( $extra_template:expr ),* };
|
||||
)?
|
||||
|
||||
$(
|
||||
generics = { $( $generic:ident = $sample:ty ),* };
|
||||
)?
|
||||
|
||||
$(
|
||||
// Match any attribute on the function, such as #[doc], #[allow(dead_code)], etc.
|
||||
$( #[ $attr:meta ] )*
|
||||
@ -76,34 +72,31 @@ macro_rules! register_templates {
|
||||
.map_err(|source| TemplateError::Render { template: $template, source })
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
pub fn check_render(&self) -> Result<(), TemplateError> {
|
||||
self.check_render_inner $( ::< $( $sample ),+ > )? ()
|
||||
}
|
||||
/// Helps rendering each template with sample data
|
||||
pub mod check {
|
||||
use super::*;
|
||||
|
||||
fn check_render_inner
|
||||
$( < $( $generic ),+ > )?
|
||||
(&self) -> Result<(), TemplateError>
|
||||
$( 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;
|
||||
for sample in samples {
|
||||
::tracing::info!(name, "Rendering template");
|
||||
self. $name (&sample)?;
|
||||
}
|
||||
let name = $template;
|
||||
for sample in samples {
|
||||
let context = serde_json::to_value(&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
|
||||
// limitations under the License.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! Templates rendering
|
||||
|
||||
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 warp::reject::Reject;
|
||||
|
||||
#[allow(missing_docs)] // TODO
|
||||
mod context;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
@ -38,14 +42,19 @@ pub use self::context::{
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Templates(Arc<Tera>);
|
||||
|
||||
/// There was an issue while loading the templates
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TemplateLoadingError {
|
||||
/// Some templates failed to compile
|
||||
#[error("could not load and compile some templates")]
|
||||
Compile(#[from] TeraError),
|
||||
|
||||
/// There are essential templates missing
|
||||
#[error("missing templates {missing:?}")]
|
||||
MissingTemplates {
|
||||
/// List of missing templates
|
||||
missing: HashSet<String>,
|
||||
/// List of templates that were loaded
|
||||
loaded: HashSet<String>,
|
||||
},
|
||||
}
|
||||
@ -146,18 +155,27 @@ impl Templates {
|
||||
}
|
||||
}
|
||||
|
||||
/// Failed to render a template
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TemplateError {
|
||||
/// Failed to prepare the context used by this template
|
||||
#[error("could not prepare context for template {template:?}")]
|
||||
Context {
|
||||
/// The name of the template being rendered
|
||||
template: &'static str,
|
||||
|
||||
/// The underlying error
|
||||
#[source]
|
||||
source: TeraError,
|
||||
},
|
||||
|
||||
/// Failed to render the template
|
||||
#[error("could not render template {template:?}")]
|
||||
Render {
|
||||
/// The name of the template being rendered
|
||||
template: &'static str,
|
||||
|
||||
/// The underlying error
|
||||
#[source]
|
||||
source: TeraError,
|
||||
},
|
||||
@ -167,7 +185,6 @@ impl Reject for TemplateError {}
|
||||
|
||||
register_templates! {
|
||||
extra = { "base.html" };
|
||||
generics = { T = EmptyContext };
|
||||
|
||||
/// Render the login page
|
||||
pub fn render_login(WithCsrf<LoginContext>) { "login.html" }
|
||||
@ -188,12 +205,26 @@ register_templates! {
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn check_all_templates() {
|
||||
fn check_builtin_templates() {
|
||||
let templates = Templates::load(None, true).unwrap();
|
||||
templates.check_render().unwrap();
|
||||
}
|
||||
|
Reference in New Issue
Block a user