+26
-34
src/http/handle_admin_denylist.rs
+26
-34
src/http/handle_admin_denylist.rs
···
4
4
response::{IntoResponse, Redirect},
5
5
Form,
6
6
};
7
-
use axum_template::RenderHtml;
8
7
use minijinja::context as template_context;
9
8
use serde::Deserialize;
10
9
use std::borrow::Cow;
11
10
12
11
use crate::{
13
-
contextual_error,
12
+
contextual_error, create_renderer,
14
13
http::{
15
-
context::{admin_template_context, AdminRequestContext},
14
+
context::AdminRequestContext,
16
15
errors::WebError,
17
16
pagination::{Pagination, PaginationView},
18
17
},
19
-
select_template,
20
18
storage::denylist::{denylist_add_or_update, denylist_list, denylist_remove},
21
19
};
22
20
···
39
37
"https://{}/admin/denylist",
40
38
admin_ctx.web_context.config.external_base
41
39
);
42
-
let default_context = admin_template_context(&admin_ctx, &canonical_url);
43
40
44
-
let render_template = select_template!("admin_denylist", false, false, admin_ctx.language);
45
-
let error_template = select_template!(false, false, admin_ctx.language);
41
+
let renderer = create_renderer!(admin_ctx.web_context, admin_ctx.language, false, false);
46
42
47
43
let (page, page_size) = pagination.admin_clamped();
48
44
49
45
let denylist = denylist_list(&admin_ctx.web_context.pool, page, page_size).await;
50
46
if let Err(err) = denylist {
51
47
return contextual_error!(
52
-
admin_ctx.web_context,
53
-
admin_ctx.language,
54
-
error_template,
55
-
default_context,
56
-
err
48
+
renderer: renderer,
49
+
err,
50
+
template_context!{}
57
51
);
58
52
}
59
53
let (total_count, mut entries) = denylist.unwrap();
···
66
60
entries.truncate(page_size as usize);
67
61
}
68
62
69
-
Ok(RenderHtml(
70
-
&render_template,
71
-
admin_ctx.web_context.engine.clone(),
72
-
template_context! { ..default_context, ..template_context! {
73
-
entries,
74
-
total_count,
75
-
pagination => pagination_view,
76
-
}},
77
-
)
78
-
.into_response())
63
+
Ok(renderer
64
+
.render_template(
65
+
"admin_denylist",
66
+
template_context! {
67
+
entries,
68
+
total_count,
69
+
pagination => pagination_view,
70
+
},
71
+
Some(&admin_ctx.current_handle),
72
+
&canonical_url,
73
+
)
74
+
.into_response())
79
75
}
80
76
81
77
pub async fn handle_admin_denylist_add(
82
78
admin_ctx: AdminRequestContext,
83
79
Form(form): Form<DenylistAddForm>,
84
80
) -> Result<impl IntoResponse, WebError> {
85
-
let error_template = select_template!(false, false, admin_ctx.language);
81
+
let renderer = create_renderer!(admin_ctx.web_context, admin_ctx.language, false, false);
86
82
87
83
if let Err(err) = denylist_add_or_update(
88
84
&admin_ctx.web_context.pool,
···
92
88
.await
93
89
{
94
90
return contextual_error!(
95
-
admin_ctx.web_context,
96
-
admin_ctx.language,
97
-
error_template,
98
-
template_context! {},
99
-
err
91
+
renderer: renderer,
92
+
err,
93
+
template_context!{}
100
94
);
101
95
}
102
96
···
107
101
admin_ctx: AdminRequestContext,
108
102
Form(form): Form<DenylistRemoveForm>,
109
103
) -> Result<impl IntoResponse, WebError> {
110
-
let error_template = select_template!(false, false, admin_ctx.language);
104
+
let renderer = create_renderer!(admin_ctx.web_context, admin_ctx.language, false, false);
111
105
112
106
if let Err(err) = denylist_remove(&admin_ctx.web_context.pool, &form.subject).await {
113
107
return contextual_error!(
114
-
admin_ctx.web_context,
115
-
admin_ctx.language,
116
-
error_template,
117
-
template_context! {},
118
-
err
108
+
renderer: renderer,
109
+
err,
110
+
template_context!{}
119
111
);
120
112
}
121
113
+9
-28
src/http/handle_admin_event.rs
+9
-28
src/http/handle_admin_event.rs
···
1
1
use anyhow::Result;
2
2
use axum::{extract::Query, response::IntoResponse};
3
-
use axum_template::RenderHtml;
4
3
use minijinja::context as template_context;
5
4
use serde::Deserialize;
6
5
7
6
use crate::{
8
-
contextual_error,
7
+
contextual_error, create_renderer,
9
8
http::{context::AdminRequestContext, errors::WebError},
10
-
select_template,
11
9
storage::event::event_get,
12
10
};
13
11
···
25
23
26
24
let canonical_url = format!("https://{}/admin/event", web_context.config.external_base);
27
25
28
-
// Create context with query parameters
29
-
let context_with_aturi = template_context! {
30
-
language => language.to_string(),
31
-
current_handle => admin_ctx.admin_handle.clone(),
32
-
canonical_url => canonical_url,
33
-
aturi => query.aturi.clone()
34
-
};
35
-
36
-
let render_template = select_template!("admin_event", false, false, language);
37
-
let error_template = select_template!(false, false, language);
26
+
// Create the template renderer with enhanced context
27
+
let renderer = create_renderer!(web_context.clone(), language, false, false);
38
28
39
29
// Get the event record by AT-URI
40
30
let event = event_get(&web_context.pool, &query.aturi).await;
41
31
if let Err(err) = event {
42
-
return contextual_error!(
43
-
web_context,
44
-
language.0,
45
-
error_template,
46
-
context_with_aturi,
47
-
err
48
-
);
32
+
return contextual_error!(renderer: renderer, err, template_context!{ aturi => query.aturi.clone() });
49
33
}
50
34
let event = event.unwrap();
51
35
···
53
37
let event_json = serde_json::to_string_pretty(&event)
54
38
.unwrap_or_else(|_| "Error formatting JSON".to_string());
55
39
56
-
Ok(RenderHtml(
57
-
&render_template,
58
-
web_context.engine.clone(),
40
+
Ok(renderer.render_template(
41
+
"admin_event",
59
42
template_context! {
60
-
language => language.to_string(),
61
-
current_handle => admin_ctx.admin_handle.clone(),
62
-
canonical_url => canonical_url,
63
43
aturi => query.aturi.clone(),
64
44
event => event,
65
45
event_json => event_json,
66
46
},
67
-
)
68
-
.into_response())
47
+
Some(&admin_ctx.admin_handle),
48
+
&canonical_url,
49
+
)?)
69
50
}
+9
-25
src/http/handle_admin_events.rs
+9
-25
src/http/handle_admin_events.rs
···
1
1
use anyhow::Result;
2
2
use axum::{extract::Query, response::IntoResponse};
3
-
use axum_template::RenderHtml;
4
3
use minijinja::context as template_context;
5
4
6
5
use crate::{
7
-
contextual_error,
6
+
contextual_error, create_renderer,
8
7
http::{
9
8
context::AdminRequestContext,
10
9
errors::WebError,
11
10
pagination::{Pagination, PaginationView},
12
11
},
13
-
select_template,
14
12
storage::event::event_list,
15
13
};
16
14
···
22
20
let web_context = admin_ctx.web_context;
23
21
24
22
let canonical_url = format!("https://{}/admin/events", web_context.config.external_base);
25
-
let default_context = template_context! {
26
-
language => language.to_string(),
27
-
current_handle => admin_ctx.admin_handle.clone(),
28
-
canonical_url => canonical_url,
29
-
};
30
23
31
-
let render_template = select_template!("admin_events", false, false, language);
32
-
let error_template = select_template!(false, false, language);
24
+
// Create the template renderer with enhanced context
25
+
let renderer = create_renderer!(web_context.clone(), language, false, false);
33
26
34
27
let (page, page_size) = pagination.admin_clamped();
35
28
36
29
let events = event_list(&web_context.pool, page, page_size).await;
37
30
if let Err(err) = events {
38
-
return contextual_error!(
39
-
web_context,
40
-
language.0,
41
-
error_template,
42
-
default_context,
43
-
err
44
-
);
31
+
return contextual_error!(renderer: renderer, err, template_context!{});
45
32
}
46
33
let (total_count, mut events) = events.unwrap();
47
34
···
53
40
events.truncate(page_size as usize);
54
41
}
55
42
56
-
Ok(RenderHtml(
57
-
&render_template,
58
-
web_context.engine.clone(),
43
+
Ok(renderer.render_template(
44
+
"admin_events",
59
45
template_context! {
60
-
language => language.to_string(),
61
-
current_handle => admin_ctx.admin_handle.clone(),
62
-
canonical_url => canonical_url,
63
46
events => events,
64
47
total_count => total_count,
65
48
pagination => pagination_view,
66
49
},
67
-
)
68
-
.into_response())
50
+
Some(&admin_ctx.admin_handle.handle),
51
+
&canonical_url,
52
+
))
69
53
}
+12
-21
src/http/handle_admin_handles.rs
+12
-21
src/http/handle_admin_handles.rs
···
4
4
response::{IntoResponse, Redirect},
5
5
};
6
6
use axum_htmx::{HxRedirect, HxRequest};
7
-
use axum_template::RenderHtml;
8
7
use http::StatusCode;
9
8
use minijinja::context as template_context;
10
9
11
10
use crate::{
12
-
contextual_error,
11
+
contextual_error, create_renderer,
13
12
http::{
14
13
context::{admin_template_context, AdminRequestContext},
15
14
errors::WebError,
16
15
pagination::{Pagination, PaginationView},
17
16
},
18
-
select_template,
19
17
storage::handle::{handle_list, handle_nuke},
20
18
};
21
19
···
27
25
"https://{}/admin/handles",
28
26
admin_ctx.web_context.config.external_base
29
27
);
30
-
let default_context = admin_template_context(&admin_ctx, &canonical_url);
31
-
32
-
let render_template = select_template!("admin_handles", false, false, admin_ctx.language);
33
-
let error_template = select_template!(false, false, admin_ctx.language);
28
+
29
+
// Create the template renderer with enhanced context
30
+
let renderer = create_renderer!(admin_ctx.web_context.clone(), admin_ctx.language, false, false);
34
31
35
32
let (page, page_size) = pagination.admin_clamped();
36
33
37
34
let handles = handle_list(&admin_ctx.web_context.pool, page, page_size).await;
38
35
if let Err(err) = handles {
39
-
return contextual_error!(
40
-
admin_ctx.web_context,
41
-
admin_ctx.language,
42
-
error_template,
43
-
default_context,
44
-
err
45
-
);
36
+
return contextual_error!(renderer: renderer, err, template_context!{});
46
37
}
47
38
let (total_count, mut handles) = handles.unwrap();
48
39
···
54
45
handles.truncate(page_size as usize);
55
46
}
56
47
57
-
Ok(RenderHtml(
58
-
&render_template,
59
-
admin_ctx.web_context.engine.clone(),
60
-
template_context! { ..default_context, ..template_context! {
48
+
Ok(renderer.render_template(
49
+
"admin_handles",
50
+
template_context! {
61
51
handles,
62
52
total_count,
63
53
pagination => pagination_view,
64
-
}},
65
-
)
66
-
.into_response())
54
+
},
55
+
Some(&admin_ctx.admin_handle),
56
+
&canonical_url,
57
+
)?)
67
58
}
68
59
69
60
pub async fn handle_admin_nuke_identity(
+12
-18
src/http/handle_admin_rsvp.rs
+12
-18
src/http/handle_admin_rsvp.rs
···
4
4
response::IntoResponse,
5
5
};
6
6
use axum_extra::extract::Cached;
7
-
use axum_template::RenderHtml;
8
7
use minijinja::context as template_context;
9
8
use serde::Deserialize;
10
9
11
10
use crate::{
12
-
contextual_error,
11
+
contextual_error, create_renderer,
13
12
http::{
14
13
context::WebContext, errors::WebError, middleware_auth::Auth, middleware_i18n::Language,
15
14
},
16
-
select_template,
17
15
storage::event::rsvp_get,
18
16
};
19
17
···
30
28
) -> Result<impl IntoResponse, WebError> {
31
29
let current_handle = auth.require_admin(&web_context.config)?;
32
30
33
-
let default_context = template_context! {
34
-
language => language.to_string(),
35
-
current_handle,
36
-
canonical_url => format!("https://{}/admin/rsvp", web_context.config.external_base),
37
-
};
31
+
let canonical_url = format!("https://{}/admin/rsvp", web_context.config.external_base);
38
32
39
-
let render_template = select_template!("admin_rsvp", false, false, language);
40
-
let error_template = select_template!(false, false, language);
33
+
// Create the template renderer with enhanced context
34
+
let renderer = create_renderer!(web_context.clone(), language, false, false);
41
35
42
36
// Fetch the RSVP
43
37
let rsvp_result = rsvp_get(&web_context.pool, &query.aturi).await;
44
38
if let Err(err) = rsvp_result {
45
-
return contextual_error!(web_context, language, error_template, default_context, err);
39
+
return contextual_error!(renderer: renderer, err, template_context!{ aturi => query.aturi.clone() });
46
40
}
47
41
let rsvp = rsvp_result.unwrap();
48
42
49
43
// Convert the RSVP to a JSON string for display
50
44
let rsvp_json = serde_json::to_string_pretty(&rsvp).unwrap_or_default();
51
45
52
-
Ok(RenderHtml(
53
-
&render_template,
54
-
web_context.engine.clone(),
55
-
template_context! { ..default_context, ..template_context! {
46
+
Ok(renderer.render_template(
47
+
"admin_rsvp",
48
+
template_context! {
56
49
rsvp,
57
50
rsvp_json,
58
-
}},
59
-
)
60
-
.into_response())
51
+
},
52
+
Some(¤t_handle),
53
+
&canonical_url,
54
+
)?)
61
55
}
+9
-29
src/http/handle_admin_rsvps.rs
+9
-29
src/http/handle_admin_rsvps.rs
···
1
1
use anyhow::Result;
2
2
use axum::{extract::Query, response::IntoResponse};
3
-
use axum_template::RenderHtml;
4
3
use minijinja::context as template_context;
5
4
use serde::Deserialize;
6
5
7
6
use crate::{
8
-
contextual_error,
7
+
contextual_error, create_renderer,
9
8
http::{
10
9
context::AdminRequestContext,
11
10
errors::WebError,
12
11
pagination::{Pagination, PaginationView},
13
12
},
14
-
select_template,
15
13
storage::event::rsvp_list,
16
14
};
17
15
···
37
35
38
36
let canonical_url = format!("https://{}/admin/rsvps", web_context.config.external_base);
39
37
40
-
// Create the context with all needed parameters
41
-
let default_context = template_context! {
42
-
language => language.to_string(),
43
-
current_handle => admin_ctx.admin_handle.clone(),
44
-
canonical_url => canonical_url,
45
-
import_success => import_success,
46
-
imported_aturi => imported_aturi,
47
-
};
48
-
49
-
let render_template = select_template!("admin_rsvps", false, false, language);
50
-
let error_template = select_template!(false, false, language);
38
+
// Create the template renderer with enhanced context
39
+
let renderer = create_renderer!(web_context.clone(), language, false, false);
51
40
52
41
let (page, page_size) = params.pagination.admin_clamped();
53
42
54
43
let rsvps = rsvp_list(&web_context.pool, page, page_size).await;
55
44
if let Err(err) = rsvps {
56
-
return contextual_error!(
57
-
web_context,
58
-
language.0,
59
-
error_template,
60
-
default_context,
61
-
err
62
-
);
45
+
return contextual_error!(renderer: renderer, err, template_context!{});
63
46
}
64
47
let (total_count, mut rsvps) = rsvps.unwrap();
65
48
···
71
54
rsvps.truncate(page_size as usize);
72
55
}
73
56
74
-
Ok(RenderHtml(
75
-
&render_template,
76
-
web_context.engine.clone(),
57
+
Ok(renderer.render_template(
58
+
"admin_rsvps",
77
59
template_context! {
78
-
language => language.to_string(),
79
-
current_handle => admin_ctx.admin_handle.clone(),
80
-
canonical_url => canonical_url,
81
60
import_success => import_success,
82
61
imported_aturi => imported_aturi,
83
62
rsvps => rsvps,
84
63
total_count => total_count,
85
64
pagination => pagination_view,
86
65
},
87
-
)
88
-
.into_response())
66
+
Some(&admin_ctx.admin_handle),
67
+
&canonical_url,
68
+
)?)
89
69
}
+85
-93
src/http/handle_create_event.rs
+85
-93
src/http/handle_create_event.rs
···
9
9
use axum_extra::extract::Form;
10
10
use axum_htmx::HxBoosted;
11
11
use axum_htmx::HxRequest;
12
-
use axum_template::RenderHtml;
13
12
use chrono::Utc;
14
13
use http::Method;
15
14
use http::StatusCode;
···
26
25
use crate::atproto::lexicon::community::lexicon::calendar::event::Status;
27
26
use crate::atproto::lexicon::community::lexicon::calendar::event::NSID;
28
27
use crate::atproto::lexicon::community::lexicon::location::Address;
29
-
use crate::contextual_error;
28
+
use crate::create_renderer;
30
29
use crate::http::context::WebContext;
30
+
use crate::http::template_renderer::TemplateRenderer;
31
31
use crate::http::errors::CommonError;
32
32
use crate::http::errors::CreateEventError;
33
33
use crate::http::errors::WebError;
···
39
39
use crate::http::middleware_i18n::Language;
40
40
use crate::http::timezones::supported_timezones;
41
41
use crate::http::utils::url_from_aturi;
42
-
use crate::select_template;
43
42
use crate::storage::event::event_insert;
44
43
45
44
use super::cache_countries::cached_countries;
···
56
55
) -> Result<impl IntoResponse, WebError> {
57
56
let current_handle = auth.require(&web_context.config.destination_key, "/event")?;
58
57
58
+
// Create the template renderer with enhanced context
59
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, hx_request);
60
+
61
+
let canonical_url = format!("https://{}/event", web_context.config.external_base);
59
62
let is_development = cfg!(debug_assertions);
60
63
61
64
let default_context = template_context! {
62
-
current_handle,
63
-
language => language.to_string(),
64
-
canonical_url => format!("https://{}/event", web_context.config.external_base),
65
65
is_development,
66
66
create_event => true,
67
67
submit_url => format!("/event"),
68
68
};
69
-
// <a href="/{{ handle_slug }}/{{ event_rkey }}" class="button">Cancel</a>
70
-
71
-
let render_template = select_template!("create_event", hx_boosted, hx_request, language);
72
-
73
-
let error_template = select_template!(hx_boosted, hx_request, language);
74
69
75
70
let (default_tz, timezones) = supported_timezones(auth.0.as_ref());
76
71
···
142
137
build_event_form.starts_at = starts_form.starts_at.clone();
143
138
}
144
139
145
-
return Ok(RenderHtml(
146
-
&render_template,
147
-
web_context.engine.clone(),
148
-
template_context! { ..default_context, ..template_context! {
140
+
return Ok(renderer.render_template(
141
+
"create_event",
142
+
template_context! {
143
+
..default_context,
149
144
build_event_form,
150
145
starts_form,
151
146
location_form,
152
147
link_form,
153
148
timezones,
154
-
}},
155
-
)
156
-
.into_response());
149
+
},
150
+
Some(¤t_handle.handle),
151
+
&canonical_url,
152
+
));
157
153
}
158
154
159
155
match build_event_form.build_state {
···
279
275
let create_record_result = client.create_record(&client_auth, event_record).await;
280
276
281
277
if let Err(err) = create_record_result {
282
-
return contextual_error!(
283
-
web_context,
284
-
language,
285
-
error_template,
286
-
default_context,
287
-
err
288
-
);
278
+
return Ok(renderer.render_error(err, default_context));
289
279
}
290
280
291
281
// create_record_result is guaranteed to be Ok since we checked for Err above
···
302
292
.await;
303
293
304
294
if let Err(err) = event_insert_result {
305
-
return contextual_error!(
306
-
web_context,
307
-
language,
308
-
error_template,
309
-
default_context,
310
-
err
311
-
);
295
+
return Ok(renderer.render_error(err, default_context));
312
296
}
313
297
314
298
let event_url =
315
299
url_from_aturi(&web_context.config.external_base, &create_record_result.uri)?;
316
300
317
-
return Ok(RenderHtml(
318
-
&render_template,
319
-
web_context.engine.clone(),
320
-
template_context! { ..default_context, ..template_context! {
301
+
return Ok(renderer.render_template(
302
+
"create_event",
303
+
template_context! {
304
+
..default_context,
321
305
build_event_form,
322
306
starts_form,
323
307
location_form,
324
308
link_form,
325
309
operation_completed => true,
326
310
event_url,
327
-
}},
328
-
)
329
-
.into_response());
311
+
},
312
+
Some(¤t_handle.handle),
313
+
&canonical_url,
314
+
));
330
315
}
331
316
}
332
317
_ => {}
333
318
}
334
319
335
-
Ok(RenderHtml(
336
-
&render_template,
337
-
web_context.engine.clone(),
338
-
template_context! { ..default_context, ..template_context! {
320
+
Ok(renderer.render_template(
321
+
"create_event",
322
+
template_context! {
323
+
..default_context,
339
324
build_event_form,
340
325
starts_form,
341
326
timezones,
342
327
location_form,
343
328
link_form,
344
-
}},
345
-
)
346
-
.into_response())
329
+
},
330
+
Some(¤t_handle.handle),
331
+
&canonical_url,
332
+
))
347
333
}
348
334
349
335
pub async fn handle_starts_at_builder(
···
366
352
367
353
let is_development = cfg!(debug_assertions);
368
354
369
-
let render_template = format!(
370
-
"create_event.{}.starts_form.html",
371
-
language.to_string().to_lowercase()
372
-
);
355
+
// Create the template renderer for HTMX partial updates
356
+
let renderer = create_renderer!(web_context.clone(), Language(language.clone()), false, true);
357
+
358
+
let canonical_url = format!("https://{}/event", web_context.config.external_base);
373
359
374
360
if starts_form.build_state.is_none() {
375
361
starts_form.build_state = Some(BuildEventContentState::default());
···
379
365
}
380
366
381
367
if method == Method::GET {
382
-
return Ok(RenderHtml(
383
-
&render_template,
384
-
web_context.engine.clone(),
368
+
return Ok(renderer.render_template(
369
+
"create_event.starts_form",
385
370
template_context! {
386
371
starts_form,
387
372
is_development,
388
373
timezones,
389
374
},
390
-
)
391
-
.into_response());
375
+
None,
376
+
&canonical_url,
377
+
));
392
378
}
393
379
394
380
if starts_form
···
424
410
}
425
411
}
426
412
427
-
Ok(RenderHtml(
428
-
&render_template,
429
-
web_context.engine.clone(),
413
+
Ok(renderer.render_template(
414
+
"create_event.starts_form",
430
415
template_context! {
431
416
starts_form,
432
417
is_development,
433
418
timezones,
434
419
},
435
-
)
436
-
.into_response())
420
+
None,
421
+
&canonical_url,
422
+
))
437
423
}
438
424
439
425
pub async fn handle_location_at_builder(
···
454
440
455
441
let is_development = cfg!(debug_assertions);
456
442
457
-
let render_template = format!(
458
-
"create_event.{}.location_form.html",
459
-
language.to_string().to_lowercase()
460
-
);
443
+
// Create the template renderer for HTMX partial updates
444
+
let renderer = create_renderer!(web_context.clone(), Language(language.clone()), false, true);
445
+
446
+
let canonical_url = format!("https://{}/event", web_context.config.external_base);
461
447
462
448
if location_form.build_state.is_none() {
463
449
location_form.build_state = Some(BuildEventContentState::default());
464
450
}
465
451
466
452
if method == Method::GET {
467
-
return Ok(RenderHtml(
468
-
&render_template,
469
-
web_context.engine.clone(),
453
+
return Ok(renderer.render_template(
454
+
"create_event.location_form",
470
455
template_context! {
471
456
location_form,
472
457
is_development
473
458
},
474
-
)
475
-
.into_response());
459
+
None,
460
+
&canonical_url,
461
+
));
476
462
}
477
463
478
464
if location_form
···
499
485
}
500
486
}
501
487
502
-
Ok(RenderHtml(
503
-
&render_template,
504
-
web_context.engine.clone(),
488
+
Ok(renderer.render_template(
489
+
"create_event.location_form",
505
490
template_context! {
506
491
location_form,
507
492
is_development,
508
493
},
509
-
)
510
-
.into_response())
494
+
None,
495
+
&canonical_url,
496
+
))
511
497
}
512
498
513
499
pub async fn handle_link_at_builder(
···
528
514
529
515
let is_development = cfg!(debug_assertions);
530
516
531
-
let render_template = format!(
532
-
"create_event.{}.link_form.html",
533
-
language.to_string().to_lowercase()
534
-
);
517
+
// Create the template renderer for HTMX partial updates
518
+
let renderer = create_renderer!(web_context.clone(), Language(language.clone()), false, true);
519
+
520
+
let canonical_url = format!("https://{}/event", web_context.config.external_base);
535
521
536
522
if link_form.build_state.is_none() {
537
523
link_form.build_state = Some(BuildEventContentState::default());
538
524
}
539
525
540
526
if method == Method::GET {
541
-
return Ok(RenderHtml(
542
-
&render_template,
543
-
web_context.engine.clone(),
527
+
return Ok(renderer.render_template(
528
+
"create_event.link_form",
544
529
template_context! {
545
530
link_form,
546
531
is_development
547
532
},
548
-
)
549
-
.into_response());
533
+
None,
534
+
&canonical_url,
535
+
));
550
536
}
551
537
552
538
if link_form
···
573
559
}
574
560
}
575
561
576
-
Ok(RenderHtml(
577
-
&render_template,
578
-
web_context.engine.clone(),
562
+
Ok(renderer.render_template(
563
+
"create_event.link_form",
579
564
template_context! {
580
565
link_form,
581
566
is_development,
582
567
},
583
-
)
584
-
.into_response())
568
+
None,
569
+
&canonical_url,
570
+
))
585
571
}
586
572
587
573
#[derive(Deserialize, Debug, Clone)]
···
591
577
592
578
pub async fn handle_location_datalist(
593
579
State(web_context): State<WebContext>,
580
+
Language(language): Language,
594
581
HxRequest(hx_request): HxRequest,
595
582
Query(location_country_hint): Query<LocationDataListHint>,
596
583
) -> Result<impl IntoResponse, WebError> {
···
598
585
return Ok(StatusCode::BAD_REQUEST.into_response());
599
586
}
600
587
588
+
// Create the template renderer for HTMX partial updates
589
+
let renderer = create_renderer!(web_context.clone(), Language(language), false, true);
590
+
591
+
let canonical_url = format!("https://{}/event", web_context.config.external_base);
592
+
601
593
let all_countries = cached_countries()?;
602
594
603
595
let locations = if let Some(value) = location_country_hint.location_country {
···
614
606
.collect::<Vec<(String, String)>>()
615
607
};
616
608
617
-
Ok(RenderHtml(
618
-
"create_event.countries_datalist.html",
619
-
web_context.engine.clone(),
609
+
Ok(renderer.render_template(
610
+
"create_event.countries_datalist",
620
611
template_context! {
621
612
locations,
622
613
},
623
-
)
624
-
.into_response())
614
+
None,
615
+
&canonical_url,
616
+
))
625
617
}
626
618
627
619
// Nick: The next two methods were adapted from https://www.thecodedmessage.com/posts/prefix-ranges/ which has no license. Thank you.
+28
-48
src/http/handle_create_rsvp.rs
+28
-48
src/http/handle_create_rsvp.rs
···
2
2
use axum::{extract::State, response::IntoResponse};
3
3
use axum_extra::extract::{Cached, Form};
4
4
use axum_htmx::{HxBoosted, HxRequest};
5
-
use axum_template::RenderHtml;
6
5
use chrono::Utc;
7
6
use http::Method;
8
7
use metrohash::MetroHash64;
···
18
17
community::lexicon::calendar::rsvp::{Rsvp, RsvpStatus, NSID},
19
18
},
20
19
},
21
-
contextual_error,
20
+
contextual_error, create_renderer,
22
21
http::{
23
22
context::WebContext,
24
23
errors::WebError,
···
27
26
rsvp_form::{BuildRSVPForm, BuildRsvpContentState},
28
27
utils::url_from_aturi,
29
28
},
30
-
select_template,
31
29
storage::event::rsvp_insert,
32
30
};
33
31
···
42
40
) -> Result<impl IntoResponse, WebError> {
43
41
let current_handle = auth.require(&web_context.config.destination_key, "/rsvp")?;
44
42
45
-
let default_context = template_context! {
46
-
current_handle,
47
-
language => language.to_string(),
48
-
canonical_url => format!("https://{}/rsvp", web_context.config.external_base),
49
-
hx_request,
50
-
hx_boosted,
51
-
};
52
-
53
-
let render_template = select_template!("create_rsvp", hx_boosted, hx_request, language);
54
-
let error_template = select_template!(hx_boosted, hx_request, language);
43
+
// Create the template renderer with enhanced context
44
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, hx_request);
45
+
46
+
let canonical_url = format!("https://{}/rsvp", web_context.config.external_base);
55
47
56
48
if build_rsvp_form.build_state.is_none() {
57
49
build_rsvp_form.build_state = Some(BuildRsvpContentState::default());
···
65
57
66
58
build_rsvp_form.build_state = Some(BuildRsvpContentState::Selecting);
67
59
68
-
return Ok(RenderHtml(
69
-
&render_template,
70
-
web_context.engine.clone(),
71
-
template_context! { ..default_context, ..template_context! {
60
+
return Ok(renderer.render_template(
61
+
"create_rsvp",
62
+
template_context! {
72
63
build_rsvp_form,
73
-
}},
74
-
)
75
-
.into_response());
64
+
},
65
+
Some(¤t_handle.handle),
66
+
&canonical_url,
67
+
));
76
68
}
77
69
78
70
match build_rsvp_form.build_state {
···
159
151
let put_record_result = client.put_record(&client_auth, rsvp_record).await;
160
152
161
153
if let Err(err) = put_record_result {
162
-
return contextual_error!(
163
-
web_context,
164
-
language,
165
-
error_template,
166
-
default_context,
167
-
err
168
-
);
154
+
return contextual_error!(renderer: renderer, err, template_context!{});
169
155
}
170
156
171
157
let create_record_result = put_record_result.unwrap();
···
181
167
.await;
182
168
183
169
if let Err(err) = rsvp_insert_result {
184
-
return contextual_error!(
185
-
web_context,
186
-
language,
187
-
error_template,
188
-
default_context,
189
-
err
190
-
);
170
+
return contextual_error!(renderer: renderer, err, template_context!{});
191
171
}
192
172
193
173
let event_url = url_from_aturi(
···
195
175
build_rsvp_form.subject_aturi.clone().unwrap().as_str(),
196
176
)?;
197
177
198
-
return Ok(RenderHtml(
199
-
&render_template,
200
-
web_context.engine.clone(),
201
-
template_context! { ..default_context, ..template_context! {
178
+
return Ok(renderer.render_template(
179
+
"create_rsvp",
180
+
template_context! {
202
181
build_rsvp_form,
203
182
event_url,
204
-
}},
205
-
)
206
-
.into_response());
183
+
},
184
+
Some(¤t_handle.handle),
185
+
&canonical_url,
186
+
));
207
187
}
208
188
}
209
189
None => unreachable!(),
210
190
}
211
191
212
-
Ok(RenderHtml(
213
-
&render_template,
214
-
web_context.engine.clone(),
215
-
template_context! { ..default_context, ..template_context! {
192
+
Ok(renderer.render_template(
193
+
"create_rsvp",
194
+
template_context! {
216
195
build_rsvp_form
217
-
}},
218
-
)
219
-
.into_response())
196
+
},
197
+
Some(¤t_handle.handle),
198
+
&canonical_url,
199
+
))
220
200
}
+53
-68
src/http/handle_edit_event.rs
+53
-68
src/http/handle_edit_event.rs
···
2
2
use axum::{extract::Path, response::IntoResponse};
3
3
use axum_extra::extract::Form;
4
4
use axum_htmx::{HxBoosted, HxRequest};
5
-
use axum_template::RenderHtml;
6
5
use chrono::Utc;
7
6
use http::{Method, StatusCode};
8
7
use minijinja::context as template_context;
···
27
26
http::timezones::supported_timezones,
28
27
http::utils::url_from_aturi,
29
28
resolve::{parse_input, InputType},
30
-
select_template,
29
+
create_renderer,
31
30
storage::{
32
31
event::{event_get, event_update_with_metadata},
33
32
handle::{handle_for_did, handle_for_handle},
···
46
45
.auth
47
46
.require(&ctx.web_context.config.destination_key, "/")?;
48
47
49
-
let default_context = template_context! {
50
-
current_handle,
51
-
language => ctx.language.to_string(),
52
-
canonical_url => format!("https://{}/{}/{}/edit", ctx.web_context.config.external_base, handle_slug, event_rkey),
53
-
create_event => false,
54
-
submit_url => format!("/{}/{}/edit", handle_slug, event_rkey),
55
-
cancel_url => format!("/{}/{}", handle_slug, event_rkey),
56
-
};
48
+
let canonical_url = format!(
49
+
"https://{}/{}/{}/edit",
50
+
ctx.web_context.config.external_base, handle_slug, event_rkey
51
+
);
57
52
58
-
let render_template = select_template!("edit_event", hx_boosted, hx_request, ctx.language);
59
-
let error_template = select_template!(hx_boosted, hx_request, ctx.language);
53
+
// Create the template renderer with enhanced context
54
+
let renderer = create_renderer!(ctx.web_context.clone(), ctx.language, hx_boosted, hx_request);
60
55
61
56
// Lookup the event
62
57
let profile = match parse_input(&handle_slug) {
···
79
74
// Check if the user is authorized to edit this event (must be the creator)
80
75
if profile.did != current_handle.did {
81
76
return contextual_error!(
82
-
ctx.web_context,
83
-
ctx.language,
84
-
error_template,
85
-
default_context,
77
+
renderer: renderer,
86
78
EditEventError::NotAuthorized,
79
+
template_context!{},
87
80
StatusCode::FORBIDDEN
88
81
);
89
82
}
90
83
91
84
let event = event_get(&ctx.web_context.pool, &lookup_aturi).await;
92
85
if let Err(err) = event {
93
-
return contextual_error!(
94
-
ctx.web_context,
95
-
ctx.language,
96
-
error_template,
97
-
default_context,
98
-
err,
99
-
StatusCode::OK
100
-
);
86
+
return contextual_error!(renderer: renderer, err, template_context!{}, StatusCode::OK);
101
87
}
102
88
103
89
let event = event.unwrap();
···
105
91
// Check if this is a community calendar event (we only support editing those)
106
92
if event.lexicon != LexiconCommunityEventNSID {
107
93
return contextual_error!(
108
-
ctx.web_context,
109
-
ctx.language,
110
-
error_template,
111
-
default_context,
94
+
renderer: renderer,
112
95
EditEventError::UnsupportedEventType,
96
+
template_context!{},
113
97
StatusCode::BAD_REQUEST
114
98
);
115
99
}
···
120
104
Ok(event) => event,
121
105
Err(_) => {
122
106
return contextual_error!(
123
-
ctx.web_context,
124
-
ctx.language,
125
-
error_template,
126
-
default_context,
107
+
renderer: renderer,
127
108
CommonError::InvalidEventFormat,
109
+
template_context!{},
128
110
StatusCode::BAD_REQUEST
129
111
);
130
112
}
···
385
367
386
368
return Ok((
387
369
StatusCode::OK,
388
-
RenderHtml(
389
-
&render_template,
390
-
ctx.web_context.engine.clone(),
391
-
template_context! { ..default_context, ..template_context! {
370
+
renderer.render_template(
371
+
"edit_event",
372
+
template_context! {
392
373
build_event_form,
393
374
starts_form,
394
375
location_form,
···
400
381
locations_editable,
401
382
location_edit_reason,
402
383
location_display_info,
403
-
}},
404
-
),
405
-
)
406
-
.into_response());
384
+
create_event => false,
385
+
submit_url => format!("/{}/{}/edit", handle_slug, event_rkey),
386
+
cancel_url => format!("/{}/{}", handle_slug, event_rkey),
387
+
},
388
+
Some(¤t_handle),
389
+
&canonical_url,
390
+
)?,
391
+
));
407
392
}
408
393
409
394
// Process form state changes just like in create_event
···
522
507
};
523
508
524
509
return contextual_error!(
525
-
ctx.web_context,
526
-
ctx.language,
527
-
error_template,
528
-
default_context,
510
+
renderer: renderer,
529
511
error,
512
+
template_context!{},
530
513
StatusCode::BAD_REQUEST
531
514
);
532
515
}
···
606
589
607
590
if let Err(err) = update_record_result {
608
591
return contextual_error!(
609
-
ctx.web_context,
610
-
ctx.language,
611
-
error_template,
612
-
default_context,
592
+
renderer: renderer,
613
593
err,
594
+
template_context!{},
614
595
StatusCode::OK
615
596
);
616
597
}
···
633
614
634
615
if let Err(err) = event_update_result {
635
616
return contextual_error!(
636
-
ctx.web_context,
637
-
ctx.language,
638
-
error_template,
639
-
default_context,
617
+
renderer: renderer,
640
618
err,
619
+
template_context!{},
641
620
StatusCode::OK
642
621
);
643
622
}
···
647
626
648
627
return Ok((
649
628
StatusCode::OK,
650
-
RenderHtml(
651
-
&render_template,
652
-
ctx.web_context.engine.clone(),
653
-
template_context! { ..default_context, ..template_context! {
629
+
renderer.render_template(
630
+
"edit_event",
631
+
template_context! {
654
632
build_event_form,
655
633
starts_form,
656
634
location_form,
···
663
641
is_development,
664
642
locations_editable,
665
643
location_edit_reason,
666
-
}},
667
-
),
668
-
)
669
-
.into_response());
644
+
create_event => false,
645
+
submit_url => format!("/{}/{}/edit", handle_slug, event_rkey),
646
+
cancel_url => format!("/{}/{}", handle_slug, event_rkey),
647
+
},
648
+
Some(¤t_handle),
649
+
&canonical_url,
650
+
)?,
651
+
));
670
652
}
671
653
}
672
654
_ => {}
···
674
656
675
657
Ok((
676
658
StatusCode::OK,
677
-
RenderHtml(
678
-
&render_template,
679
-
ctx.web_context.engine.clone(),
680
-
template_context! { ..default_context, ..template_context! {
659
+
renderer.render_template(
660
+
"edit_event",
661
+
template_context! {
681
662
build_event_form,
682
663
starts_form,
683
664
location_form,
···
688
669
is_development,
689
670
locations_editable,
690
671
location_edit_reason,
691
-
}},
692
-
),
693
-
)
694
-
.into_response())
672
+
create_event => false,
673
+
submit_url => format!("/{}/{}/edit", handle_slug, event_rkey),
674
+
cancel_url => format!("/{}/{}", handle_slug, event_rkey),
675
+
},
676
+
Some(¤t_handle),
677
+
&canonical_url,
678
+
)?,
679
+
))
695
680
}
+40
-54
src/http/handle_import.rs
+40
-54
src/http/handle_import.rs
···
4
4
};
5
5
use axum_extra::extract::Cached;
6
6
use axum_htmx::{HxBoosted, HxRequest};
7
-
use axum_template::RenderHtml;
8
7
use http::StatusCode;
9
8
use minijinja::context as template_context;
10
9
use serde::Deserialize;
···
30
29
},
31
30
},
32
31
},
33
-
contextual_error,
32
+
contextual_error, create_renderer,
34
33
http::{
35
34
context::WebContext,
36
35
errors::{ImportError, WebError},
37
36
middleware_auth::Auth,
38
37
middleware_i18n::Language,
39
38
},
40
-
select_template,
41
39
storage::event::{event_insert_with_metadata, rsvp_insert_with_metadata},
42
40
};
43
41
···
50
48
) -> Result<impl IntoResponse, WebError> {
51
49
let current_handle = auth.require(&web_context.config.destination_key, "/import")?;
52
50
53
-
let default_context = template_context! {
54
-
current_handle,
55
-
language => language.to_string(),
56
-
canonical_url => format!("https://{}/import", web_context.config.external_base),
57
-
};
58
-
59
-
let render_template = select_template!("import", hx_boosted, hx_request, language);
51
+
// Create the template renderer with enhanced context
52
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, hx_request);
53
+
54
+
let canonical_url = format!("https://{}/import", web_context.config.external_base);
60
55
61
-
Ok(RenderHtml(
62
-
&render_template,
63
-
web_context.engine.clone(),
64
-
default_context,
65
-
)
66
-
.into_response())
56
+
Ok(renderer.render_template(
57
+
"import",
58
+
template_context! {},
59
+
Some(¤t_handle.handle),
60
+
&canonical_url,
61
+
))
67
62
}
68
63
69
64
#[derive(Debug, Deserialize)]
···
85
80
return Ok(StatusCode::BAD_REQUEST.into_response());
86
81
}
87
82
88
-
let render_template = select_template!("import", false, true, language);
89
-
let error_template = select_template!(false, hx_request, language);
83
+
// Create the template renderer for HTMX partial updates
84
+
let renderer = create_renderer!(web_context.clone(), Language(language), false, true);
85
+
86
+
let canonical_url = format!("https://{}/import", web_context.config.external_base);
90
87
91
88
let collections = [
92
89
LEXICON_COMMUNITY_EVENT_NSID,
···
166
163
}
167
164
Err(err) => {
168
165
return contextual_error!(
169
-
web_context,
170
-
language,
171
-
error_template,
172
-
template_context! {},
173
-
ImportError::FailedToListCommunityEvents(err.to_string())
166
+
renderer: renderer,
167
+
ImportError::FailedToListCommunityEvents(err.to_string()),
168
+
template_context!{}
174
169
)
175
170
}
176
171
}
···
238
233
}
239
234
Err(err) => {
240
235
return contextual_error!(
241
-
web_context,
242
-
language,
243
-
error_template,
244
-
template_context! {},
245
-
ImportError::FailedToListCommunityRSVPs(err.to_string())
236
+
renderer: renderer,
237
+
ImportError::FailedToListCommunityRSVPs(err.to_string()),
238
+
template_context!{}
246
239
)
247
240
}
248
241
}
···
296
289
}
297
290
Err(err) => {
298
291
return contextual_error!(
299
-
web_context,
300
-
language,
301
-
error_template,
302
-
template_context! {},
303
-
ImportError::FailedToListSmokesignalEvents(err.to_string())
292
+
renderer: renderer,
293
+
ImportError::FailedToListSmokesignalEvents(err.to_string()),
294
+
template_context!{}
304
295
)
305
296
}
306
297
}
···
364
355
}
365
356
Err(err) => {
366
357
return contextual_error!(
367
-
web_context,
368
-
language,
369
-
error_template,
370
-
template_context! {},
371
-
ImportError::FailedToListSmokesignalRSVPs(err.to_string())
358
+
renderer: renderer,
359
+
ImportError::FailedToListSmokesignalRSVPs(err.to_string()),
360
+
template_context!{}
372
361
)
373
362
}
374
363
}
375
364
}
376
365
_ => {
377
366
return contextual_error!(
378
-
web_context,
379
-
language,
380
-
error_template,
381
-
template_context! {},
382
-
ImportError::UnsupportedCollectionType(collection.clone())
367
+
renderer: renderer,
368
+
ImportError::UnsupportedCollectionType(collection.clone()),
369
+
template_context!{}
383
370
)
384
371
}
385
372
};
386
373
387
-
Ok(RenderHtml(
388
-
&render_template,
389
-
web_context.engine.clone(),
390
-
template_context! {
391
-
current_handle,
392
-
language => language.to_string(),
393
-
canonical_url => format!("https://{}/import", web_context.config.external_base),
394
-
..render_context,
395
-
},
396
-
)
397
-
.into_response())
374
+
Ok(renderer
375
+
.render_template(
376
+
"import",
377
+
template_context! {
378
+
..render_context,
379
+
},
380
+
Some(¤t_handle.handle),
381
+
&canonical_url,
382
+
)
383
+
.into_response())
398
384
}
+10
-18
src/http/handle_index.rs
+10
-18
src/http/handle_index.rs
···
7
7
};
8
8
use axum_extra::extract::Cached;
9
9
use axum_htmx::HxBoosted;
10
-
use axum_template::RenderHtml;
11
10
12
11
use minijinja::context as template_context;
13
12
use serde::{Deserialize, Serialize};
14
13
15
14
use crate::{
16
-
contextual_error,
15
+
contextual_error, create_renderer,
17
16
http::{
18
17
context::WebContext,
19
18
errors::WebError,
···
23
22
pagination::{Pagination, PaginationView},
24
23
tab_selector::TabSelector,
25
24
},
26
-
select_template,
27
25
storage::event::event_list_recently_updated,
28
26
};
29
27
···
54
52
pagination: Query<Pagination>,
55
53
tab_selector: Query<TabSelector>,
56
54
) -> Result<impl IntoResponse, WebError> {
57
-
let render_template = select_template!("index", hx_boosted, false, language);
58
-
let error_template = select_template!(false, false, language);
55
+
// Create the template renderer with enhanced context
56
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
57
+
58
+
let canonical_url = format!("https://{}/", web_context.config.external_base);
59
59
60
60
let (page, page_size) = pagination.clamped();
61
61
let tab: HomeTab = tab_selector.0.into();
···
70
70
match tab_events {
71
71
Ok(values) => values,
72
72
Err(err) => {
73
-
return contextual_error!(
74
-
web_context,
75
-
language,
76
-
error_template,
77
-
template_context! {},
78
-
err
79
-
);
73
+
return contextual_error!(renderer: renderer, err, template_context!{});
80
74
}
81
75
}
82
76
};
···
114
108
115
109
Ok((
116
110
http::StatusCode::OK,
117
-
RenderHtml(
118
-
&render_template,
119
-
web_context.engine.clone(),
111
+
renderer.render_template(
112
+
"index",
120
113
template_context! {
121
-
current_handle => auth.0,
122
-
language => language.to_string(),
123
-
canonical_url => format!("https://{}/", web_context.config.external_base),
124
114
tab => tab.to_string(),
125
115
events,
126
116
pagination => pagination_view,
127
117
},
118
+
auth.0.as_ref().map(|h| h.handle.as_str()),
119
+
&canonical_url,
128
120
),
129
121
)
130
122
.into_response())
+70
-83
src/http/handle_migrate_event.rs
+70
-83
src/http/handle_migrate_event.rs
···
5
5
};
6
6
use axum_extra::extract::Cached;
7
7
use axum_htmx::{HxBoosted, HxRequest};
8
-
use axum_template::RenderHtml;
9
8
use http::StatusCode;
10
9
use minijinja::context as template_context;
11
10
use std::collections::HashMap;
···
26
25
},
27
26
},
28
27
},
29
-
contextual_error,
28
+
create_renderer,
30
29
http::{
31
-
context::WebContext, errors::MigrateEventError, errors::WebError, middleware_auth::Auth,
32
-
middleware_i18n::Language, utils::url_from_aturi,
30
+
context::WebContext,
31
+
errors::{MigrateEventError, WebError},
32
+
middleware_auth::Auth,
33
+
middleware_i18n::Language,
34
+
template_renderer::TemplateRenderer,
35
+
utils::url_from_aturi,
33
36
},
34
37
resolve::{parse_input, InputType},
35
-
select_template,
36
38
storage::{
37
39
event::{event_get, event_insert_with_metadata},
38
40
handle::{handle_for_did, handle_for_handle, model::Handle},
···
49
51
) -> Result<impl IntoResponse, WebError> {
50
52
let current_handle = auth.require(&web_context.config.destination_key, "/")?;
51
53
52
-
// Configure templates
53
-
let default_context = template_context! {
54
-
current_handle,
55
-
language => language.to_string(),
56
-
canonical_url => format!("https://{}/{}/{}/migrate", web_context.config.external_base, handle_slug, event_rkey),
57
-
};
58
-
let render_template = select_template!("migrate_event", hx_boosted, hx_request, language);
59
-
let error_template = select_template!(hx_boosted, hx_request, language);
54
+
// Create the template renderer with enhanced context
55
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, hx_request);
56
+
let canonical_url = format!("https://{}/{}/{}/migrate", renderer.web_context.config.external_base, handle_slug, event_rkey);
60
57
61
58
// Lookup the user handle/profile
62
59
let profile: Result<Handle> = match parse_input(&handle_slug) {
···
70
67
};
71
68
72
69
if let Err(err) = profile {
73
-
return contextual_error!(
74
-
web_context,
75
-
language,
76
-
error_template,
77
-
default_context,
70
+
return Ok(renderer.render_error(
78
71
err,
79
-
StatusCode::NOT_FOUND
80
-
);
72
+
template_context! {
73
+
current_handle => current_handle.handle.as_str(),
74
+
canonical_url => canonical_url,
75
+
},
76
+
));
81
77
}
82
78
let profile = profile.unwrap();
83
79
···
86
82
87
83
// Check if the user is authorized to migrate this event (must be the event creator/organizer)
88
84
if profile.did != current_handle.did {
89
-
return contextual_error!(
90
-
web_context,
91
-
language,
92
-
error_template,
93
-
default_context,
85
+
return Ok(renderer.render_error(
94
86
MigrateEventError::NotAuthorized,
95
-
StatusCode::FORBIDDEN
96
-
);
87
+
template_context! {
88
+
current_handle => current_handle.handle.as_str(),
89
+
canonical_url => canonical_url,
90
+
},
91
+
));
97
92
}
98
93
99
94
// Fetch the event from the database
100
95
let event = event_get(&web_context.pool, &source_aturi).await;
101
96
if let Err(err) = event {
102
-
return contextual_error!(
103
-
web_context,
104
-
language,
105
-
error_template,
106
-
default_context,
97
+
return Ok(renderer.render_error(
107
98
err,
108
-
StatusCode::OK
109
-
);
99
+
template_context! {
100
+
current_handle => current_handle.handle.as_str(),
101
+
canonical_url => canonical_url,
102
+
},
103
+
));
110
104
}
111
105
let event = event.unwrap();
112
106
···
114
108
if event.lexicon != SMOKESIGNAL_NSID {
115
109
// If it's already the community event type, we don't need to migrate
116
110
if event.lexicon == COMMUNITY_NSID {
117
-
return contextual_error!(
118
-
web_context,
119
-
language,
120
-
error_template,
121
-
default_context,
111
+
return Ok(renderer.render_error(
122
112
MigrateEventError::AlreadyMigrated,
123
-
StatusCode::BAD_REQUEST
124
-
);
113
+
template_context! {
114
+
current_handle => current_handle.handle.as_str(),
115
+
canonical_url => canonical_url,
116
+
},
117
+
));
125
118
}
126
119
127
-
return contextual_error!(
128
-
web_context,
129
-
language,
130
-
error_template,
131
-
default_context,
120
+
return Ok(renderer.render_error(
132
121
MigrateEventError::UnsupportedEventType,
133
-
StatusCode::BAD_REQUEST
134
-
);
122
+
template_context! {
123
+
current_handle => current_handle.handle.as_str(),
124
+
canonical_url => canonical_url,
125
+
},
126
+
));
135
127
}
136
128
137
129
// Parse the legacy event
138
130
let legacy_event = match serde_json::from_value::<SmokeSignalEvent>(event.record.0.clone()) {
139
131
Ok(event) => event,
140
132
Err(err) => {
141
-
return contextual_error!(
142
-
web_context,
143
-
language,
144
-
error_template,
145
-
default_context,
133
+
return Ok(renderer.render_error(
146
134
err,
147
-
StatusCode::BAD_REQUEST
148
-
);
135
+
template_context! {
136
+
current_handle => current_handle.handle.as_str(),
137
+
canonical_url => canonical_url,
138
+
},
139
+
));
149
140
}
150
141
};
151
142
···
251
242
// Check if a record already exists at the target AT-URI
252
243
let existing_event = event_get(&web_context.pool, &migrated_aturi).await;
253
244
if existing_event.is_ok() {
254
-
return contextual_error!(
255
-
web_context,
256
-
language,
257
-
error_template,
258
-
default_context,
245
+
return Ok(renderer.render_error(
259
246
MigrateEventError::DestinationExists,
260
-
StatusCode::CONFLICT
261
-
);
247
+
template_context! {
248
+
current_handle => current_handle.handle.as_str(),
249
+
canonical_url => canonical_url,
250
+
},
251
+
));
262
252
}
263
253
264
254
// Set up XRPC client
···
285
275
// Write to the PDS
286
276
let update_record_result = client.put_record(&client_auth, update_record_request).await;
287
277
if let Err(err) = update_record_result {
288
-
return contextual_error!(
289
-
web_context,
290
-
language,
291
-
error_template,
292
-
default_context,
278
+
return Ok(renderer.render_error(
293
279
err,
294
-
StatusCode::OK
295
-
);
280
+
template_context! {
281
+
current_handle => current_handle.handle.as_str(),
282
+
canonical_url => canonical_url,
283
+
},
284
+
));
296
285
}
297
286
// update_record_result is guaranteed to be Ok at this point since we checked for Err above
298
-
let update_record_result = update_record_result?;
287
+
let update_record_result = update_record_result.unwrap();
299
288
300
289
// We already have the migrated AT-URI defined above
301
290
···
312
301
.await;
313
302
314
303
if let Err(err) = migrated_event_insert_result {
315
-
return contextual_error!(
316
-
web_context,
317
-
language,
318
-
error_template,
319
-
default_context,
304
+
return Ok(renderer.render_error(
320
305
err,
321
-
StatusCode::OK
322
-
);
306
+
template_context! {
307
+
current_handle => current_handle.handle.as_str(),
308
+
canonical_url => canonical_url,
309
+
},
310
+
));
323
311
}
324
312
325
313
// Generate URL for the migrated event
326
314
let migrated_event_url = url_from_aturi(&web_context.config.external_base, &migrated_aturi)?;
327
315
328
316
// Return success with migration complete template
329
-
Ok(RenderHtml(
330
-
&render_template,
331
-
web_context.engine.clone(),
317
+
Ok(renderer.render_template(
318
+
"migrate_event",
332
319
template_context! {
333
320
migrated_event_url => migrated_event_url,
334
321
source_aturi => source_aturi,
···
336
323
event_name => name,
337
324
source_lexicon => SMOKESIGNAL_NSID,
338
325
target_lexicon => COMMUNITY_NSID,
339
-
..default_context
340
326
},
341
-
)
342
-
.into_response())
327
+
Some(current_handle.handle.as_str()),
328
+
&canonical_url,
329
+
))
343
330
}
+43
-58
src/http/handle_oauth_login.rs
+43
-58
src/http/handle_oauth_login.rs
···
3
3
use axum::{extract::State, response::IntoResponse};
4
4
use axum_extra::extract::{Cached, Form, Query};
5
5
use axum_htmx::{HxBoosted, HxRedirect, HxRequest};
6
-
use axum_template::RenderHtml;
7
6
use base64::{engine::general_purpose, Engine as _};
8
7
use http::StatusCode;
9
8
use minijinja::context as template_context;
···
14
13
use std::borrow::Cow;
15
14
16
15
use crate::{
17
-
contextual_error,
16
+
contextual_error, create_renderer,
18
17
did::{plc::query as plc_query, web::query as web_query},
19
18
http::{
20
19
context::WebContext, errors::LoginError, errors::WebError, middleware_auth::Auth,
···
23
22
jose,
24
23
oauth::{oauth_init, pds_resources},
25
24
resolve::{parse_input, resolve_subject, InputType},
26
-
select_template,
27
25
storage::{
28
26
denylist::denylist_exists,
29
27
handle::handle_warm_up,
···
51
49
Query(destination): Query<Destination>,
52
50
Form(login_form): Form<OAuthLoginForm>,
53
51
) -> Result<impl IntoResponse, WebError> {
52
+
// Create the template renderer with enhanced context
53
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, hx_request);
54
+
55
+
let canonical_url = format!("https://{}/oauth/login", web_context.config.external_base);
56
+
let current_handle = auth.0.as_ref().map(|h| h.handle.as_str()).unwrap_or("");
57
+
54
58
let default_context = template_context! {
55
-
current_handle => auth.0,
56
-
language => language.to_string(),
57
-
canonical_url => format!("https://{}/oauth/login", web_context.config.external_base),
58
59
destination => destination.destination,
59
60
};
60
61
61
-
let render_template = select_template!("login", hx_boosted, hx_request, language);
62
-
let error_template = select_template!(hx_boosted, hx_request, language);
63
-
64
62
if let Some(subject) = login_form.handle {
65
63
let resolved_did = resolve_subject(
66
64
&web_context.http_client,
···
70
68
.await;
71
69
72
70
if let Err(err) = resolved_did {
73
-
return contextual_error!(
74
-
web_context,
75
-
language,
76
-
render_template,
77
-
template_context! { ..default_context.clone(), ..template_context! {
78
-
handle_error => true,
79
-
handle_input => subject,
80
-
}},
81
-
err
82
-
);
71
+
let error_context = template_context! {
72
+
..default_context.clone(),
73
+
handle_error => true,
74
+
handle_input => subject,
75
+
};
76
+
return contextual_error!(renderer: renderer, err, error_context);
83
77
}
84
78
85
79
let resolved_did = resolved_did.unwrap();
···
100
94
let did_document = match query_results {
101
95
Ok(value) => value,
102
96
Err(err) => {
103
-
return contextual_error!(
104
-
web_context,
105
-
language,
106
-
render_template,
107
-
template_context! { ..default_context.clone(), ..template_context! {
108
-
handle_error => true,
109
-
handle_input => subject,
110
-
}},
111
-
err
112
-
);
97
+
let error_context = template_context! {
98
+
..default_context.clone(),
99
+
handle_error => true,
100
+
handle_input => subject,
101
+
};
102
+
return contextual_error!(renderer: renderer, err, error_context);
113
103
}
114
104
};
115
105
···
147
137
let pds = match did_document.pds_endpoint() {
148
138
Some(value) => value,
149
139
None => {
150
-
return contextual_error!(
151
-
web_context,
152
-
language,
153
-
render_template,
154
-
template_context! { ..default_context.clone(), ..template_context! {
155
-
handle_error => true,
156
-
handle_input => subject,
157
-
}},
158
-
LoginError::NoPDS
159
-
);
140
+
let error_context = template_context! {
141
+
..default_context.clone(),
142
+
handle_error => true,
143
+
handle_input => subject,
144
+
};
145
+
return contextual_error!(renderer: renderer, LoginError::NoPDS, error_context);
160
146
}
161
147
};
162
148
163
149
let primary_handle = match did_document.primary_handle() {
164
150
Some(value) => value,
165
151
None => {
166
-
return contextual_error!(
167
-
web_context,
168
-
language,
169
-
render_template,
170
-
template_context! { ..default_context.clone(), ..template_context! {
171
-
handle_error => true,
172
-
handle_input => subject,
173
-
}},
174
-
LoginError::NoHandle
175
-
);
152
+
let error_context = template_context! {
153
+
..default_context.clone(),
154
+
handle_error => true,
155
+
handle_input => subject,
156
+
};
157
+
return contextual_error!(renderer: renderer, LoginError::NoHandle, error_context);
176
158
}
177
159
};
178
160
179
161
if let Err(err) =
180
162
handle_warm_up(&web_context.pool, &did_document.id, primary_handle, pds).await
181
163
{
182
-
return contextual_error!(web_context, language, error_template, default_context, err);
164
+
return contextual_error!(renderer: renderer, err, default_context);
183
165
}
184
166
185
167
let state: String = rand::thread_rng()
···
296
278
return Ok(Redirect::temporary(destination.as_str()).into_response());
297
279
}
298
280
299
-
Ok(RenderHtml(
300
-
&render_template,
301
-
web_context.engine.clone(),
302
-
template_context! { ..default_context, ..template_context! {
303
-
destination => destination.destination,
304
-
}},
305
-
)
306
-
.into_response())
281
+
let final_context = template_context! {
282
+
..default_context,
283
+
destination => destination.destination,
284
+
};
285
+
286
+
Ok(renderer.render_template(
287
+
"login",
288
+
final_context,
289
+
Some(current_handle),
290
+
&canonical_url,
291
+
))
307
292
}
308
293
309
294
pub fn gen_pkce() -> (String, String) {
+16
-9
src/http/handle_oauth_logout.rs
+16
-9
src/http/handle_oauth_logout.rs
···
5
5
};
6
6
use axum_extra::extract::{cookie::Cookie, PrivateCookieJar};
7
7
use axum_htmx::{HxRedirect, HxRequest};
8
-
use axum_template::RenderHtml;
9
8
use http::StatusCode;
10
9
use minijinja::context as template_context;
11
10
12
-
use crate::http::{
13
-
context::WebContext, errors::WebError, middleware_auth::AUTH_COOKIE_NAME,
14
-
middleware_i18n::Language,
11
+
use crate::{
12
+
create_renderer,
13
+
http::{
14
+
context::WebContext, errors::WebError, middleware_auth::AUTH_COOKIE_NAME,
15
+
middleware_i18n::Language,
16
+
},
15
17
};
16
18
17
19
pub async fn handle_logout(
···
26
28
let hx_redirect = HxRedirect::try_from("/");
27
29
if let Err(err) = hx_redirect {
28
30
tracing::error!("Failed to create HxLocation: {}", err);
29
-
return Ok(RenderHtml(
30
-
format!("alert.{}.partial.html", language.to_string().to_lowercase()),
31
-
web_context.engine.clone(),
31
+
32
+
// Create the template renderer for error handling
33
+
let renderer = create_renderer!(web_context.clone(), Language(language), false, true);
34
+
let canonical_url = format!("https://{}/", web_context.config.external_base);
35
+
36
+
return Ok(renderer.render_template(
37
+
"alert.partial",
32
38
template_context! { message => "Internal Server Error" },
33
-
)
34
-
.into_response());
39
+
None,
40
+
&canonical_url,
41
+
));
35
42
}
36
43
let hx_redirect = hx_redirect.unwrap();
37
44
Ok((StatusCode::OK, hx_redirect, "").into_response())
+45
-38
src/http/handle_policy.rs
+45
-38
src/http/handle_policy.rs
···
2
2
use axum::{extract::State, response::IntoResponse};
3
3
use axum_extra::extract::Cached;
4
4
use axum_htmx::HxBoosted;
5
-
use axum_template::RenderHtml;
6
5
7
6
use minijinja::context as template_context;
8
7
9
8
use crate::{
9
+
create_renderer,
10
10
http::{
11
11
context::WebContext, errors::WebError, middleware_auth::Auth, middleware_i18n::Language,
12
12
},
13
-
select_template,
14
13
};
15
14
16
15
pub async fn handle_privacy_policy(
···
19
18
Language(language): Language,
20
19
Cached(auth): Cached<Auth>,
21
20
) -> Result<impl IntoResponse, WebError> {
22
-
let render_template = select_template!("privacy-policy", hx_boosted, false, language);
21
+
// Create the template renderer with enhanced context
22
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
23
+
24
+
let canonical_url = format!("https://{}/privacy-policy", web_context.config.external_base);
25
+
let current_handle = auth.0.as_ref().map(|h| h.handle.as_str()).unwrap_or("");
26
+
23
27
Ok((
24
28
http::StatusCode::OK,
25
-
RenderHtml(
26
-
&render_template,
27
-
web_context.engine.clone(),
28
-
template_context! {
29
-
current_handle => auth.0,
30
-
language => language.to_string(),
31
-
canonical_url => format!("https://{}/privacy-policy", web_context.config.external_base),
32
-
},
29
+
renderer.render_template(
30
+
"privacy-policy",
31
+
template_context! {},
32
+
Some(current_handle),
33
+
&canonical_url,
33
34
),
34
35
)
35
36
.into_response())
···
41
42
Language(language): Language,
42
43
Cached(auth): Cached<Auth>,
43
44
) -> Result<impl IntoResponse, WebError> {
44
-
let render_template = select_template!("terms-of-service", hx_boosted, false, language);
45
+
// Create the template renderer with enhanced context
46
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
47
+
48
+
let canonical_url = format!("https://{}/terms-of-service", web_context.config.external_base);
49
+
let current_handle = auth.0.as_ref().map(|h| h.handle.as_str()).unwrap_or("");
50
+
45
51
Ok((
46
52
http::StatusCode::OK,
47
-
RenderHtml(
48
-
&render_template,
49
-
web_context.engine.clone(),
50
-
template_context! {
51
-
current_handle => auth.0,
52
-
language => language.to_string(),
53
-
canonical_url => format!("https://{}/terms-of-service", web_context.config.external_base),
54
-
},
53
+
renderer.render_template(
54
+
"terms-of-service",
55
+
template_context! {},
56
+
Some(current_handle),
57
+
&canonical_url,
55
58
),
56
59
)
57
60
.into_response())
···
63
66
Language(language): Language,
64
67
Cached(auth): Cached<Auth>,
65
68
) -> Result<impl IntoResponse, WebError> {
66
-
let render_template = select_template!("cookie-policy", hx_boosted, false, language);
69
+
// Create the template renderer with enhanced context
70
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
71
+
72
+
let canonical_url = format!("https://{}/cookie-policy", web_context.config.external_base);
73
+
let current_handle = auth.0.as_ref().map(|h| h.handle.as_str()).unwrap_or("");
74
+
67
75
Ok((
68
76
http::StatusCode::OK,
69
-
RenderHtml(
70
-
&render_template,
71
-
web_context.engine.clone(),
72
-
template_context! {
73
-
current_handle => auth.0,
74
-
language => language.to_string(),
75
-
canonical_url => format!("https://{}/cookie-policy", web_context.config.external_base),
76
-
},
77
+
renderer.render_template(
78
+
"cookie-policy",
79
+
template_context! {},
80
+
Some(current_handle),
81
+
&canonical_url,
77
82
),
78
83
)
79
84
.into_response())
···
85
90
Language(language): Language,
86
91
Cached(auth): Cached<Auth>,
87
92
) -> Result<impl IntoResponse, WebError> {
88
-
let render_template = select_template!("acknowledgement", hx_boosted, false, language);
93
+
// Create the template renderer with enhanced context
94
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
95
+
96
+
let canonical_url = format!("https://{}/acknowledgement", web_context.config.external_base);
97
+
let current_handle = auth.0.as_ref().map(|h| h.handle.as_str()).unwrap_or("");
98
+
89
99
Ok((
90
100
http::StatusCode::OK,
91
-
RenderHtml(
92
-
&render_template,
93
-
web_context.engine.clone(),
94
-
template_context! {
95
-
current_handle => auth.0,
96
-
language => language.to_string(),
97
-
canonical_url => format!("https://{}/acknowledgement", web_context.config.external_base),
98
-
},
101
+
renderer.render_template(
102
+
"acknowledgement",
103
+
template_context! {},
104
+
Some(current_handle),
105
+
&canonical_url,
99
106
),
100
107
)
101
108
.into_response())
+20
-27
src/http/handle_profile.rs
+20
-27
src/http/handle_profile.rs
···
3
3
use axum::response::IntoResponse;
4
4
use axum_extra::extract::Query;
5
5
use axum_htmx::{HxBoosted, HxRequest};
6
-
use axum_template::RenderHtml;
7
6
use chrono_tz::Tz;
8
7
use http::StatusCode;
9
8
use minijinja::context as template_context;
···
11
10
use std::fmt;
12
11
13
12
use crate::{
14
-
contextual_error,
13
+
contextual_error, create_renderer,
15
14
http::{
16
15
context::UserRequestContext,
17
16
errors::{CommonError, WebError},
···
20
19
tab_selector::{TabLink, TabSelector},
21
20
utils::build_url,
22
21
},
23
-
select_template,
24
22
storage::{
25
23
errors::StorageError,
26
24
event::{event_list_did_recently_updated, model::EventWithRole},
···
57
55
pagination: Query<Pagination>,
58
56
tab_selector: Query<TabSelector>,
59
57
) -> Result<impl IntoResponse, WebError> {
60
-
let default_context = template_context! {
61
-
language => ctx.language.to_string(),
62
-
current_handle => ctx.current_handle,
63
-
};
64
-
65
-
let render_template = select_template!("profile", hx_boosted, hx_request, ctx.language);
66
-
let error_template = select_template!(false, hx_request, ctx.language);
58
+
let renderer = create_renderer!(ctx.web_context, ctx.language, hx_boosted, hx_request);
67
59
68
60
if !handle_slug.starts_with("did:web:")
69
61
&& !handle_slug.starts_with("did:plc:")
70
62
&& !handle_slug.starts_with('@')
71
63
{
72
64
return contextual_error!(
73
-
ctx.web_context,
74
-
ctx.language,
75
-
error_template,
76
-
default_context,
65
+
renderer: renderer,
77
66
CommonError::InvalidHandleSlug,
67
+
template_context!{},
78
68
StatusCode::NOT_FOUND
79
69
);
80
70
}
···
91
81
92
82
if let Err(err) = profile {
93
83
return contextual_error!(
94
-
ctx.web_context,
95
-
ctx.language,
96
-
error_template,
97
-
default_context,
84
+
renderer: renderer,
98
85
err,
86
+
template_context!{},
99
87
StatusCode::NOT_FOUND
100
88
);
101
89
}
···
142
130
Ok(values) => values,
143
131
Err(err) => {
144
132
return contextual_error!(
145
-
ctx.web_context,
146
-
ctx.language,
147
-
error_template,
148
-
default_context,
133
+
renderer: renderer,
149
134
err,
135
+
template_context!{},
150
136
StatusCode::NOT_FOUND
151
137
);
152
138
}
···
193
179
active: tab == ProfileTab::RecentlyUpdated,
194
180
}];
195
181
182
+
let canonical_url = format!(
183
+
"https://{}/{}",
184
+
ctx.web_context.config.external_base,
185
+
handle_slug
186
+
);
187
+
196
188
Ok((
197
189
StatusCode::OK,
198
-
RenderHtml(
199
-
&render_template,
200
-
ctx.web_context.engine.clone(),
201
-
template_context! { ..default_context, ..template_context! {
190
+
renderer.render_template(
191
+
"profile",
192
+
template_context! {
202
193
tab => tab.to_string(),
203
194
tabs => tab_links,
204
195
events,
205
196
pagination => pagination_view,
206
-
}},
197
+
},
198
+
ctx.current_handle.as_ref().map(|h| &h.handle),
199
+
&canonical_url,
207
200
),
208
201
)
209
202
.into_response())
+33
-67
src/http/handle_settings.rs
+33
-67
src/http/handle_settings.rs
···
2
2
use axum::{extract::State, response::IntoResponse};
3
3
use axum_extra::extract::{Cached, Form};
4
4
use axum_htmx::HxBoosted;
5
-
use axum_template::RenderHtml;
6
5
use http::StatusCode;
7
6
use minijinja::context as template_context;
8
7
use serde::Deserialize;
···
10
9
use unic_langid::LanguageIdentifier;
11
10
12
11
use crate::{
13
-
contextual_error,
12
+
contextual_error, create_renderer,
14
13
http::{
15
14
context::WebContext, errors::WebError, middleware_auth::Auth, middleware_i18n::Language,
16
15
timezones::supported_timezones,
17
16
},
18
-
select_template,
19
17
storage::handle::{handle_for_did, handle_update_field, HandleField},
20
18
};
21
19
···
38
36
// Require authentication
39
37
let current_handle = auth.require(&web_context.config.destination_key, "/settings")?;
40
38
41
-
let default_context = template_context! {
42
-
current_handle => current_handle.clone(),
43
-
language => language.to_string(),
44
-
canonical_url => format!("https://{}/settings", web_context.config.external_base),
45
-
};
46
-
47
-
let render_template = select_template!("settings", hx_boosted, false, language);
39
+
// Create the template renderer with enhanced context
40
+
let renderer = create_renderer!(web_context.clone(), Language(language), hx_boosted, false);
41
+
42
+
let canonical_url = format!("https://{}/settings", web_context.config.external_base);
48
43
49
44
// Get available timezones
50
45
let (_, timezones) = supported_timezones(Some(¤t_handle));
···
60
55
// Render the form
61
56
Ok((
62
57
StatusCode::OK,
63
-
RenderHtml(
64
-
&render_template,
65
-
web_context.engine.clone(),
58
+
renderer.render_template(
59
+
"settings",
66
60
template_context! {
67
61
timezones => timezones,
68
62
languages => supported_languages,
69
-
..default_context,
70
63
},
64
+
Some(¤t_handle.handle),
65
+
&canonical_url,
71
66
),
72
67
)
73
68
.into_response())
···
82
77
) -> Result<impl IntoResponse, WebError> {
83
78
let current_handle = auth.require_flat()?;
84
79
85
-
let default_context = template_context! {
86
-
current_handle => current_handle.clone(),
87
-
language => language.to_string(),
88
-
};
89
-
90
-
let error_template = select_template!(false, true, language);
91
-
let render_template = format!("settings.{}.tz.html", language.to_string().to_lowercase());
80
+
// Create the template renderer for partial updates
81
+
let renderer = create_renderer!(web_context.clone(), Language(language), false, true);
82
+
83
+
let canonical_url = format!("https://{}/settings", web_context.config.external_base);
92
84
93
85
let (_, timezones) = supported_timezones(Some(¤t_handle));
94
86
···
96
88
|| timezone_form.timezone == current_handle.tz
97
89
|| !timezones.contains(&timezone_form.timezone.as_str())
98
90
{
99
-
return contextual_error!(
100
-
web_context,
101
-
language,
102
-
error_template,
103
-
default_context,
104
-
"error-xxx Invalid timezone"
105
-
);
91
+
return contextual_error!(renderer: renderer, "Invalid timezone", template_context!{});
106
92
}
107
93
108
94
if let Err(err) = handle_update_field(
···
112
98
)
113
99
.await
114
100
{
115
-
return contextual_error!(web_context, language, error_template, default_context, err);
101
+
return contextual_error!(renderer: renderer, err, template_context!{});
116
102
}
117
103
118
104
let current_handle = match handle_for_did(&web_context.pool, ¤t_handle.did).await {
119
105
Ok(value) => value,
120
106
Err(err) => {
121
-
return contextual_error!(web_context, language, error_template, default_context, err);
107
+
return contextual_error!(renderer: renderer, err, template_context!{});
122
108
}
123
109
};
124
110
125
111
Ok((
126
112
StatusCode::OK,
127
-
RenderHtml(
128
-
&render_template,
129
-
web_context.engine.clone(),
113
+
renderer.render_template(
114
+
"settings.tz",
130
115
template_context! {
131
116
timezone_updated => true,
132
117
timezones,
133
-
current_handle,
134
-
..default_context
135
118
},
119
+
Some(¤t_handle.handle),
120
+
&canonical_url,
136
121
),
137
122
)
138
123
.into_response())
···
147
132
) -> Result<impl IntoResponse, WebError> {
148
133
let current_handle = auth.require_flat()?;
149
134
150
-
let default_context = template_context! {
151
-
current_handle => current_handle.clone(),
152
-
language => language.to_string(),
153
-
};
154
-
155
-
let error_template = select_template!(false, true, language);
156
-
let render_template = format!(
157
-
"settings.{}.language.html",
158
-
language.to_string().to_lowercase()
159
-
);
135
+
// Create the template renderer for partial updates
136
+
let renderer = create_renderer!(web_context.clone(), Language(language), false, true);
137
+
138
+
let canonical_url = format!("https://{}/settings", web_context.config.external_base);
160
139
161
140
// Get the list of supported languages
162
141
let supported_languages = web_context
···
167
146
.collect::<Vec<String>>();
168
147
169
148
if language_form.language.is_empty() || language_form.language == current_handle.language {
170
-
return contextual_error!(
171
-
web_context,
172
-
language,
173
-
error_template,
174
-
default_context,
175
-
"error-xxx Invalid language"
176
-
);
149
+
return contextual_error!(renderer: renderer, "Invalid language", template_context!{});
177
150
}
178
151
179
152
let lang_id = match language_form.language.parse::<LanguageIdentifier>() {
180
153
Ok(value) => value,
181
154
Err(err) => {
182
-
return contextual_error!(web_context, language, error_template, default_context, err);
155
+
return contextual_error!(renderer: renderer, err, template_context!{});
183
156
}
184
157
};
185
158
···
189
162
.iter()
190
163
.any(|l| l == &lang_id)
191
164
{
192
-
return contextual_error!(
193
-
web_context,
194
-
language,
195
-
error_template,
196
-
default_context,
197
-
"error-xxx Invalid language"
198
-
);
165
+
return contextual_error!(renderer: renderer, "Invalid language", template_context!{});
199
166
}
200
167
201
168
if let Err(err) = handle_update_field(
···
205
172
)
206
173
.await
207
174
{
208
-
return contextual_error!(web_context, language, error_template, default_context, err);
175
+
return contextual_error!(renderer: renderer, err, template_context!{});
209
176
}
210
177
211
178
let current_handle = match handle_for_did(&web_context.pool, ¤t_handle.did).await {
212
179
Ok(value) => value,
213
180
Err(err) => {
214
-
return contextual_error!(web_context, language, error_template, default_context, err);
181
+
return contextual_error!(renderer: renderer, err, template_context!{});
215
182
}
216
183
};
217
184
218
185
Ok((
219
186
StatusCode::OK,
220
-
RenderHtml(
221
-
&render_template,
222
-
web_context.engine.clone(),
187
+
renderer.render_template(
188
+
"settings.lang",
223
189
template_context! {
224
-
current_handle,
225
190
language_updated => true,
226
191
languages => supported_languages,
227
-
..default_context
228
192
},
193
+
Some(¤t_handle.handle),
194
+
&canonical_url,
229
195
),
230
196
)
231
197
.into_response())
+15
-33
src/http/handle_view_event.rs
+15
-33
src/http/handle_view_event.rs
···
6
6
response::{IntoResponse, Redirect},
7
7
};
8
8
use axum_htmx::HxBoosted;
9
-
use axum_template::RenderHtml;
10
9
use http::StatusCode;
11
10
use minijinja::context as template_context;
12
11
use serde::{Deserialize, Serialize};
···
14
13
use crate::atproto::lexicon::community::lexicon::calendar::event::NSID;
15
14
use crate::atproto::lexicon::events::smokesignal::calendar::event::NSID as SMOKESIGNAL_EVENT_NSID;
16
15
use crate::contextual_error;
16
+
use crate::create_renderer;
17
17
use crate::http::context::UserRequestContext;
18
18
use crate::http::errors::CommonError;
19
19
use crate::http::errors::ViewEventError;
···
25
25
use crate::http::utils::url_from_aturi;
26
26
use crate::resolve::parse_input;
27
27
use crate::resolve::InputType;
28
-
use crate::select_template;
29
28
use crate::storage::event::count_event_rsvps;
30
29
use crate::storage::event::event_exists;
31
30
use crate::storage::event::event_get;
···
93
92
tab_selector: Query<TabSelector>,
94
93
collection_param: Query<CollectionParam>,
95
94
) -> Result<impl IntoResponse, WebError> {
96
-
let default_context = template_context! {
97
-
language => ctx.language.to_string(),
98
-
current_handle => ctx.current_handle,
99
-
};
95
+
let event_url = format!(
96
+
"https://{}/event/{}/{}",
97
+
ctx.web_context.config.external_base, handle_slug, event_rkey
98
+
);
100
99
101
-
let render_template = select_template!("view_event", hx_boosted, false, ctx.language);
102
-
let error_template = select_template!(hx_boosted, false, ctx.language);
100
+
// Create the template renderer with enhanced context
101
+
let renderer = create_renderer!(ctx.web_context.clone(), ctx.language, hx_boosted, false);
103
102
104
103
let profile: Result<Handle, WebError> = match parse_input(&handle_slug) {
105
104
Ok(InputType::Handle(handle)) => handle_for_handle(&ctx.web_context.pool, &handle)
···
114
113
};
115
114
116
115
if let Err(err) = profile {
117
-
return contextual_error!(
118
-
ctx.web_context,
119
-
ctx.language,
120
-
error_template,
121
-
default_context,
122
-
err,
123
-
StatusCode::NOT_FOUND
124
-
);
116
+
return contextual_error!(renderer: renderer, err, template_context!{}, StatusCode::NOT_FOUND);
125
117
}
126
118
127
119
let profile = profile.unwrap();
···
244
236
}
245
237
246
238
if let Err(err) = event_result {
247
-
return contextual_error!(
248
-
ctx.web_context,
249
-
ctx.language,
250
-
error_template,
251
-
default_context,
252
-
err,
253
-
StatusCode::NOT_FOUND
254
-
);
239
+
return contextual_error!(renderer: renderer, err, template_context!{}, StatusCode::NOT_FOUND);
255
240
}
256
241
257
242
let mut event = event_result.unwrap();
···
449
434
450
435
Ok((
451
436
StatusCode::OK,
452
-
RenderHtml(
453
-
&render_template,
454
-
ctx.web_context.engine.clone(),
437
+
renderer.render_template(
438
+
"view_event",
455
439
template_context! {
456
-
current_handle => ctx.current_handle,
457
-
language => ctx.language.to_string(),
458
-
canonical_url => event_url,
459
440
event => event_with_counts,
460
441
is_self,
461
442
can_edit,
···
479
460
SMOKESIGNAL_EVENT_NSID => SMOKESIGNAL_EVENT_NSID,
480
461
using_SMOKESIGNAL_EVENT_NSID => collection == SMOKESIGNAL_EVENT_NSID,
481
462
},
482
-
),
483
-
)
484
-
.into_response())
463
+
ctx.current_handle.as_ref(),
464
+
&event_url,
465
+
)?,
466
+
))
485
467
}
486
468
487
469
#[cfg(test)]