Skip to content

Commit e4f31e6

Browse files
authored
Merge pull request #168 from dandi/mv-title
Pass site title to Templater, not DandiDav
2 parents 8d058fe + 807251a commit e4f31e6

File tree

3 files changed

+83
-90
lines changed

3 files changed

+83
-90
lines changed

src/dav/html.rs

Lines changed: 81 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,22 @@ use time::OffsetDateTime;
1515
static COLLECTION_TEMPLATE: &str = include_str!("templates/collection.html.tera");
1616

1717
/// A template manager
18-
pub(crate) struct Templater(Tera);
18+
pub(crate) struct Templater {
19+
/// Tera templater
20+
engine: Tera,
21+
22+
/// Site title to display in HTML responses
23+
title: String,
24+
}
1925

2026
impl Templater {
21-
/// Create a new templater and load all templates into it
27+
/// Create a new templater with site title `title` and load all templates
28+
/// into it
2229
///
2330
/// # Errors
2431
///
2532
/// If any template fails to load, a [`TemplateError::Load`] is returned.
26-
pub(crate) fn load() -> Result<Self, TemplateError> {
33+
pub(crate) fn new(title: String) -> Result<Self, TemplateError> {
2734
let mut engine = Tera::default();
2835
engine.register_filter("formatsize", FormatSizeFilter);
2936
engine
@@ -32,37 +39,77 @@ impl Templater {
3239
template_name: "collection.html",
3340
source,
3441
})?;
35-
Ok(Templater(engine))
42+
Ok(Templater { engine, title })
3643
}
3744

3845
/// Render an HTML document containing a table listing the resources in
39-
/// `entries` using the site title `title`. `pathparts` contains the
40-
/// individual components of the request URL path.
46+
/// `entries`. `pathparts` contains the individual components of the
47+
/// request URL path.
4148
pub(super) fn render_collection(
4249
&self,
4350
entries: Vec<DavResource>,
44-
title: &str,
4551
pathparts: Vec<Component>,
4652
) -> Result<String, TemplateError> {
47-
self.render_collection_from_context(CollectionContext::new(entries, title, pathparts))
48-
}
49-
50-
fn render_collection_from_context(
51-
&self,
52-
context: CollectionContext,
53-
) -> Result<String, TemplateError> {
53+
let template_name = "collection.html";
54+
let colctx = self.collection_context(entries, pathparts);
5455
let context =
55-
Context::from_serialize(context).map_err(|source| TemplateError::MakeContext {
56-
template_name: "collection.html",
56+
Context::from_serialize(colctx).map_err(|source| TemplateError::MakeContext {
57+
template_name,
5758
source,
5859
})?;
59-
self.0
60-
.render("collection.html", &context)
60+
self.engine
61+
.render(template_name, &context)
6162
.map_err(|source| TemplateError::Render {
62-
template_name: "collection.html",
63+
template_name,
6364
source,
6465
})
6566
}
67+
68+
/// Construct the context for displaying the given `entries`. `pathparts`
69+
/// contains the individual components of the request URL path.
70+
fn collection_context(
71+
&self,
72+
entries: Vec<DavResource>,
73+
pathparts: Vec<Component>,
74+
) -> CollectionContext {
75+
let mut rows = entries.into_iter().map(ColRow::from).collect::<Vec<_>>();
76+
rows.sort_unstable();
77+
if let Some((_, pp)) = pathparts.split_last() {
78+
rows.insert(
79+
0,
80+
ColRow::parentdir(Href::from_path(&abs_dir_from_components(pp))),
81+
);
82+
}
83+
let title_path = abs_dir_from_components(&pathparts);
84+
let title = format!("{} \u{2014} {}", self.title, title_path);
85+
CollectionContext {
86+
title,
87+
breadcrumbs: self.make_breadcrumbs(pathparts),
88+
rows,
89+
package_url: env!("CARGO_PKG_REPOSITORY"),
90+
package_version: env!("CARGO_PKG_VERSION"),
91+
package_commit: option_env!("GIT_COMMIT"),
92+
}
93+
}
94+
95+
/// Create breadcrumbs for the given request URL path components
96+
fn make_breadcrumbs(&self, pathparts: Vec<Component>) -> Vec<Link> {
97+
let mut links = Vec::with_capacity(pathparts.len().saturating_add(1));
98+
let mut cumpath = String::from("/");
99+
links.push(Link {
100+
text: self.title.clone(),
101+
href: Href::from_path(&cumpath),
102+
});
103+
for p in pathparts {
104+
cumpath.push_str(&p);
105+
cumpath.push('/');
106+
links.push(Link {
107+
text: p.into(),
108+
href: Href::from_path(&cumpath),
109+
});
110+
}
111+
links
112+
}
66113
}
67114

68115
/// Context to provide to the `collection.html` template
@@ -88,32 +135,6 @@ struct CollectionContext {
88135
package_commit: Option<&'static str>,
89136
}
90137

91-
impl CollectionContext {
92-
/// Construct the context for displaying the given `entries` using the site
93-
/// title `title`. `pathparts` contains the individual components of the
94-
/// request URL path.
95-
fn new(entries: Vec<DavResource>, title: &str, pathparts: Vec<Component>) -> CollectionContext {
96-
let mut rows = entries.into_iter().map(ColRow::from).collect::<Vec<_>>();
97-
rows.sort_unstable();
98-
if let Some((_, pp)) = pathparts.split_last() {
99-
rows.insert(
100-
0,
101-
ColRow::parentdir(Href::from_path(&abs_dir_from_components(pp))),
102-
);
103-
}
104-
let title_path = abs_dir_from_components(&pathparts);
105-
let full_title = format!("{title} \u{2014} {title_path}");
106-
CollectionContext {
107-
title: full_title,
108-
breadcrumbs: make_breadcrumbs(title, pathparts),
109-
rows,
110-
package_url: env!("CARGO_PKG_REPOSITORY"),
111-
package_version: env!("CARGO_PKG_VERSION"),
112-
package_commit: option_env!("GIT_COMMIT"),
113-
}
114-
}
115-
}
116-
117138
/// A hyperlink to display in an HTML document
118139
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
119140
struct Link {
@@ -165,7 +186,7 @@ struct ColRow {
165186

166187
impl ColRow {
167188
/// Construct a `ColRow` representing the parent of the current collection,
168-
/// served at `href`
189+
/// with the parent being served at `href`
169190
fn parentdir(href: Href) -> ColRow {
170191
ColRow {
171192
name: "..".to_owned(),
@@ -261,27 +282,6 @@ fn maybe_timestamp<S: Serializer>(
261282
}
262283
}
263284

264-
/// Create breadcrumbs for the given request URL path components.
265-
///
266-
/// `title` is the site title, for use as the text of the first breadcrumb.
267-
fn make_breadcrumbs(title: &str, pathparts: Vec<Component>) -> Vec<Link> {
268-
let mut links = Vec::with_capacity(pathparts.len().saturating_add(1));
269-
let mut cumpath = String::from("/");
270-
links.push(Link {
271-
text: title.to_owned(),
272-
href: Href::from_path(&cumpath),
273-
});
274-
for p in pathparts {
275-
cumpath.push_str(&p);
276-
cumpath.push('/');
277-
links.push(Link {
278-
text: p.into(),
279-
href: Href::from_path(&cumpath),
280-
});
281-
}
282-
links
283-
}
284-
285285
/// Given an iterator of `&Component` values, join them together with forward
286286
/// slashes and add a leading & trailing slash.
287287
fn abs_dir_from_components<'a, I>(iter: I) -> String
@@ -344,7 +344,7 @@ mod tests {
344344
assert_eq!(formatsize(size), s);
345345
}
346346

347-
mod render_collection_from_context {
347+
mod render_collection {
348348
use super::*;
349349
use crate::dav::{DavContent, DavResourceWithChildren};
350350
use pretty_assertions::assert_eq;
@@ -353,7 +353,7 @@ mod tests {
353353

354354
#[test]
355355
fn basic() {
356-
let templater = Templater::load().unwrap();
356+
let templater = Templater::new("Dandidav Test".to_owned()).unwrap();
357357
let entries = vec![
358358
DavResource::Collection(DavCollection {
359359
path: Some("foo/bar/baz/a.zarr/".parse().unwrap()),
@@ -421,16 +421,16 @@ mod tests {
421421
metadata_url: None,
422422
}),
423423
];
424-
let context = CollectionContext::new(
425-
entries,
426-
"Dandidav Test",
427-
vec![
428-
"foo".parse().unwrap(),
429-
"bar".parse().unwrap(),
430-
"baz".parse().unwrap(),
431-
],
432-
);
433-
let rendered = templater.render_collection_from_context(context).unwrap();
424+
let rendered = templater
425+
.render_collection(
426+
entries,
427+
vec![
428+
"foo".parse().unwrap(),
429+
"bar".parse().unwrap(),
430+
"baz".parse().unwrap(),
431+
],
432+
)
433+
.unwrap();
434434
let commit_str = match option_env!("GIT_COMMIT") {
435435
Some(s) => Cow::from(format!(", commit {s}")),
436436
None => Cow::from(""),
@@ -451,14 +451,13 @@ mod tests {
451451

452452
#[test]
453453
fn root() {
454-
let templater = Templater::load().unwrap();
454+
let templater = Templater::new("Dandidav Test".to_owned()).unwrap();
455455
let DavResourceWithChildren::Collection { children, .. } =
456456
DavResourceWithChildren::root()
457457
else {
458458
panic!("DavResourceWithChildren::root() should be a Collection");
459459
};
460-
let context = CollectionContext::new(children, "Dandidav Test", Vec::new());
461-
let rendered = templater.render_collection_from_context(context).unwrap();
460+
let rendered = templater.render_collection(children, Vec::new()).unwrap();
462461
let commit_str = match option_env!("GIT_COMMIT") {
463462
Some(s) => Cow::from(format!(", commit {s}")),
464463
None => Cow::from(""),

src/dav/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ pub(crate) struct DandiDav {
4545
/// Manager for templating of HTML responses
4646
pub(crate) templater: Templater,
4747

48-
/// Site title to display in HTML responses
49-
pub(crate) title: String,
50-
5148
/// Whether `GET` requests for blob assets should be responded to with
5249
/// redirects to S3 (`true`) or to Archive download URLs that then redirect
5350
/// to S3 (`false`). The latter setting results in the final response
@@ -133,9 +130,7 @@ impl DandiDav {
133130
) -> Result<Response<Body>, DavError> {
134131
match self.get_resource_with_children(path).await? {
135132
DavResourceWithChildren::Collection { children, .. } => {
136-
let html = self
137-
.templater
138-
.render_collection(children, &self.title, pathparts)?;
133+
let html = self.templater.render_collection(children, pathparts)?;
139134
Ok(([(CONTENT_TYPE, HTML_CONTENT_TYPE)], html).into_response())
140135
}
141136
DavResourceWithChildren::Item(DavItem {

src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,11 @@ async fn run() -> anyhow::Result<()> {
9898
let args = Arguments::parse();
9999
let dandi = DandiClient::new(args.api_url)?;
100100
let zarrman = ZarrManClient::new()?;
101-
let templater = Templater::load()?;
101+
let templater = Templater::new(args.title)?;
102102
let dav = Arc::new(DandiDav {
103103
dandi,
104104
zarrman,
105105
templater,
106-
title: args.title,
107106
prefer_s3_redirects: args.prefer_s3_redirects,
108107
});
109108
let app = Router::new()

0 commit comments

Comments
 (0)