Commit

Author:

Hash:

Timestamp:

+77 -145 +/-15 browse

Kevin Schoon [me@kevinschoon.com]

335ba580261377adcc81fda44d3a9fb79f9ae670

Thu, 04 Jan 2024 11:57:58 +0000 (1.5 years ago)

flatten out navigation, more mail progress
1diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md
2index c27faf8..0180dbb 100644
3--- a/ATTRIBUTIONS.md
4+++ b/ATTRIBUTIONS.md
5 @@ -3,6 +3,8 @@
6 Ayllu would not be possible without many free software projects.
7
8 [Git](https://git-scm.com/)
9+ [Meli](https://meli-email.org/)
10+ [Mailpot](https://git.meli-email.org/meli/mailpot)
11
12 ## Many [Rust](https://www.rust-lang.org/) Libraries
13
14 diff --git a/src/config.rs b/src/config.rs
15index 9cdd349..0895b9d 100644
16--- a/src/config.rs
17+++ b/src/config.rs
18 @@ -175,11 +175,21 @@ impl Xmpp {
19 }
20
21 #[derive(Deserialize, Serialize, Clone, Debug, Default)]
22+ pub struct SubscriptionPolicy {
23+ pub send_confirmation: bool,
24+ pub kind: String,
25+ }
26+
27+ #[derive(Deserialize, Serialize, Clone, Debug, Default)]
28 pub struct MailingList {
29 pub id: String,
30 pub name: Option<String>,
31 pub address: String,
32+ pub request_address: String,
33 pub description: String,
34+ pub topics: Vec<String>,
35+ pub post_policy: String,
36+ pub subscription_policy: SubscriptionPolicy,
37 }
38
39 #[derive(Deserialize, Serialize, Clone, Debug, Default)]
40 @@ -280,8 +290,7 @@ impl Configurable for Config {
41 Err(e) => {
42 return Err(format!(
43 "failed to load themes from path: {} ({})",
44- self.web.themes_path,
45- e
46+ self.web.themes_path, e
47 )
48 .into())
49 }
50 @@ -378,9 +387,4 @@ Disallow: /*/*/chart/*
51 // opts.render.github_pre_lang = false;
52 opts
53 }
54-
55- // returns if any discussion plugins are enabled
56- pub fn discuss_enabled(&self) -> bool {
57- self.mail.is_some() || self.xmpp.is_some()
58- }
59 }
60 diff --git a/src/web2/routes/about.rs b/src/web2/routes/about.rs
61index cb9d015..71f1fd2 100644
62--- a/src/web2/routes/about.rs
63+++ b/src/web2/routes/about.rs
64 @@ -16,7 +16,7 @@ pub async fn serve(
65 ctx.insert("title", "about");
66 ctx.insert(
67 "nav_elements",
68- &navigation::global("about", cfg.discuss_enabled()),
69+ &navigation::global("about", cfg.mail.is_some()),
70 );
71 let options = ComrakOptions::default();
72 let mut plugins = ComrakPlugins::default();
73 diff --git a/src/web2/routes/config.rs b/src/web2/routes/config.rs
74index 0b6f19b..859122a 100644
75--- a/src/web2/routes/config.rs
76+++ b/src/web2/routes/config.rs
77 @@ -22,7 +22,7 @@ pub async fn serve(
78 ctx.insert("themes", &cfg.web.themes);
79 ctx.insert(
80 "nav_elements",
81- &navigation::global("config", cfg.discuss_enabled()),
82+ &navigation::global("config", cfg.mail.is_some()),
83 );
84 let body = templates.render("config.html", &ctx)?;
85 Ok(Html(body))
86 diff --git a/src/web2/routes/discuss.rs b/src/web2/routes/discuss.rs
87deleted file mode 100644
88index c723d3b..0000000
89--- a/src/web2/routes/discuss.rs
90+++ /dev/null
91 @@ -1,32 +0,0 @@
92- use axum::{extract::Extension, response::Html};
93-
94- use crate::config::Config;
95- use crate::web2::error::Error;
96- use crate::web2::middleware::rpc_initiator::{Initiator, Kind as InitiatorKind};
97- use crate::web2::middleware::template::Template;
98- use crate::web2::util;
99- use crate::web2::util::navigation;
100-
101- pub async fn serve(
102- Extension(cfg): Extension<Config>,
103- Extension(initiator): Extension<Initiator>,
104- Extension((templates, mut ctx)): Extension<Template>,
105- ) -> Result<Html<String>, Error> {
106- ctx.insert("title", "discuss");
107- ctx.insert(
108- "nav_elements",
109- &navigation::global("", cfg.discuss_enabled()),
110- );
111- ctx.insert("discnav", &util::navigation::discnav("overview"));
112- match initiator.clone().client(InitiatorKind::Xmpp) {
113- Some(_client) => {}
114- None => {}
115- };
116- match initiator.client(InitiatorKind::Mail) {
117- Some(_client) => {}
118- None => {}
119- };
120- // ctx.insert("lists", &cfg.mail.unwrap().lists);
121- let body = templates.render("discuss.html", &ctx)?;
122- Ok(Html(body))
123- }
124 diff --git a/src/web2/routes/index.rs b/src/web2/routes/index.rs
125index 3f6d7d3..77f109d 100644
126--- a/src/web2/routes/index.rs
127+++ b/src/web2/routes/index.rs
128 @@ -103,10 +103,7 @@ pub async fn index(
129 }
130 ctx.insert("title", "ayllu");
131 ctx.insert("collections", &collections);
132- ctx.insert(
133- "nav_elements",
134- &navigation::global("", cfg.discuss_enabled()),
135- );
136+ ctx.insert("nav_elements", &navigation::global("", cfg.mail.is_some()));
137 let body = templates.render("index.html", &ctx)?;
138 Ok(Html(body))
139 }
140 @@ -128,10 +125,7 @@ pub async fn collection(
141 let entry = entry.unwrap();
142 let repositories = load_repositories(entry.path.as_str(), &db).await?;
143 ctx.insert("title", "ayllu");
144- ctx.insert(
145- "nav_elements",
146- &navigation::global("", cfg.discuss_enabled()),
147- );
148+ ctx.insert("nav_elements", &navigation::global("", cfg.mail.is_some()));
149 ctx.insert("collection", &entry.clone());
150 ctx.insert("repositories", &repositories);
151 ctx.insert("is_hidden", &entry.hidden.is_some_and(|x| x));
152 diff --git a/src/web2/routes/mail.rs b/src/web2/routes/mail.rs
153index d835715..e08efa4 100644
154--- a/src/web2/routes/mail.rs
155+++ b/src/web2/routes/mail.rs
156 @@ -9,13 +9,13 @@ use crate::config::Config;
157 use crate::web2::error::Error;
158 use crate::web2::middleware::rpc_initiator::{Initiator, Kind as InitiatorKind};
159 use crate::web2::middleware::template::Template;
160- use crate::web2::util;
161 use crate::web2::util::navigation;
162 use ayllu_api::mail_capnp::server::Client as MailClient;
163
164 #[derive(Deserialize)]
165 pub struct Params {
166 pub list_id: String,
167+ pub thread_id: Option<String>,
168 pub message_id: Option<String>,
169 }
170
171 @@ -44,8 +44,7 @@ pub async fn lists(
172 Extension((templates, mut ctx)): Extension<Template>,
173 ) -> Result<Html<String>, Error> {
174 ctx.insert("title", "lists");
175- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
176- ctx.insert("discnav", &util::navigation::discnav("mail"));
177+ ctx.insert("nav_elements", &navigation::global("mail", true));
178 // TODO: add stats method and display like xmpp
179 ctx.insert("lists", &cfg.mail.unwrap().lists.clone());
180 // ctx.insert("lists", &cfg.mail.unwrap().lists);
181 @@ -70,9 +69,8 @@ pub async fn threads(
182 ))),
183 }?;
184 ctx.insert("title", &format!("list {}", list.address));
185- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
186+ ctx.insert("nav_elements", &navigation::global("mail", true));
187 ctx.insert("list", list);
188- ctx.insert("discnav", &util::navigation::discnav("mail"));
189
190 let mail_client = initiator.client(InitiatorKind::Mail).unwrap();
191 let mut threads = mail_client
192 @@ -99,6 +97,7 @@ pub async fn threads(
193 .await?;
194 threads.sort_by(|first, second| second.timestamp.cmp(&first.timestamp));
195 ctx.insert("threads", &threads);
196+ ctx.insert("request_email", &list.request_address);
197 let body = templates.render("threads.html", &ctx)?;
198 Ok(Html(body))
199 }
200 @@ -124,7 +123,7 @@ pub async fn thread(
201 let mut req = c.read_thread_request();
202 req.get().set_id(params.list_id.as_str().into());
203 req.get()
204- .set_message_id(params.message_id.unwrap().as_str().into());
205+ .set_message_id(params.thread_id.unwrap().as_str().into());
206 let result = req.send().promise.await?;
207 for message in result.get()?.get_thread()? {
208 messages.push(Message {
209 @@ -140,8 +139,7 @@ pub async fn thread(
210 })
211 .await?;
212 ctx.insert("title", &format!("list {}", list.address));
213- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
214- ctx.insert("discnav", &util::navigation::discnav("mail"));
215+ ctx.insert("nav_elements", &navigation::global("mail", true));
216 ctx.insert("list", list);
217 ctx.insert("list_id", &list.id);
218 ctx.insert("messages", &messages);
219 @@ -149,7 +147,7 @@ pub async fn thread(
220 Ok(Html(body))
221 }
222
223- pub async fn post(
224+ pub async fn message(
225 Path(params): Path<Params>,
226 Extension(initiator): Extension<Initiator>,
227 Extension(cfg): Extension<Config>,
228 @@ -183,8 +181,7 @@ pub async fn post(
229 })
230 .await?;
231 ctx.insert("title", &format!("list {}", list.address));
232- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
233- ctx.insert("discnav", &util::navigation::discnav("mail"));
234+ ctx.insert("nav_elements", &navigation::global("mail", true));
235 ctx.insert("list", list);
236 ctx.insert("list_id", &list.id);
237 ctx.insert("message", &message);
238 diff --git a/src/web2/routes/mod.rs b/src/web2/routes/mod.rs
239index b3b25fc..ebb476d 100644
240--- a/src/web2/routes/mod.rs
241+++ b/src/web2/routes/mod.rs
242 @@ -8,7 +8,6 @@ pub mod builds;
243 pub mod chart;
244 pub mod commit;
245 pub mod config;
246- pub mod discuss;
247 pub mod finger;
248 pub mod index;
249 pub mod log;
250 diff --git a/src/web2/routes/xmpp.rs b/src/web2/routes/xmpp.rs
251index 3187057..a2dac61 100644
252--- a/src/web2/routes/xmpp.rs
253+++ b/src/web2/routes/xmpp.rs
254 @@ -9,7 +9,6 @@ use crate::web2::error::Error;
255 use crate::web2::extractors::config::ConfigReader;
256 use crate::web2::middleware::rpc_initiator::{Initiator, Kind as InitiatorKind};
257 use crate::web2::middleware::template::Template;
258- use crate::web2::util;
259 use crate::web2::util::navigation;
260 use ayllu_api::xmpp_capnp::server::Client as XmppClient;
261
262 @@ -34,8 +33,7 @@ pub async fn channels(
263 Extension(initiator): Extension<Initiator>,
264 ) -> Result<Html<String>, Error> {
265 ctx.insert("title", "Discussions");
266- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
267- ctx.insert("discnav", &util::navigation::discnav("xmpp"));
268+ ctx.insert("nav_elements", &navigation::global("xmpp", true));
269 let xmpp_client = initiator.client(InitiatorKind::Xmpp).unwrap();
270 let channels = xmpp_client
271 .invoke(move |c: XmppClient| async move {
272 @@ -72,8 +70,7 @@ pub async fn channel(
273 Extension(initiator): Extension<Initiator>,
274 ) -> Result<Html<String>, Error> {
275 ctx.insert("title", "lists");
276- ctx.insert("nav_elements", &navigation::global("dicsuss", true));
277- ctx.insert("discnav", &util::navigation::discnav("xmpp"));
278+ ctx.insert("nav_elements", &navigation::global("xmpp", true));
279 ctx.insert("channel", &params.channel);
280 let xmpp_client = initiator.client(InitiatorKind::Xmpp).unwrap();
281 let messages = xmpp_client
282 diff --git a/src/web2/server.rs b/src/web2/server.rs
283index 653173b..1ede61a 100644
284--- a/src/web2/server.rs
285+++ b/src/web2/server.rs
286 @@ -30,7 +30,6 @@ use crate::web2::routes::builds;
287 use crate::web2::routes::chart;
288 use crate::web2::routes::commit;
289 use crate::web2::routes::config;
290- use crate::web2::routes::discuss;
291 use crate::web2::routes::finger;
292 use crate::web2::routes::index;
293 use crate::web2::routes::log as log_route;
294 @@ -171,48 +170,35 @@ pub async fn serve(cfg: &Config) -> Result<(), Box<dyn Error>> {
295 )),
296 )
297 .nest(
298- "/discuss",
299+ "/mail",
300 Router::new()
301- .route("/", routing::get(discuss::serve))
302+ .route("/", routing::get(mail::lists))
303+ .route("/:list_id", routing::get(mail::threads))
304+ .route("/:list_id/thread/:thread_id", routing::get(mail::thread))
305+ .route("/:list_id/message/:message_id", routing::get(mail::message))
306 .layer(from_fn_with_state(
307- Arc::new(cfg.clone()),
308- rpc_initiator::optional,
309+ Arc::new((cfg.clone(), templates.clone(), mail_required_plugins)),
310+ rpc_initiator::required,
311 ))
312 .layer(from_fn_with_state(
313 Arc::new((cfg.clone(), templates.clone())),
314 template::middleware,
315+ )),
316+ )
317+ .nest(
318+ "/xmpp",
319+ Router::new()
320+ .route("/", routing::get(xmpp::channels))
321+ .route("/:channel", routing::get(xmpp::channel))
322+ .route("/:channel/:last_message", routing::get(xmpp::channel))
323+ .layer(from_fn_with_state(
324+ Arc::new((cfg.clone(), templates.clone(), xmpp_required_plugins)),
325+ rpc_initiator::required,
326 ))
327- .nest(
328- "/mail",
329- Router::new()
330- .route("/", routing::get(mail::lists))
331- .route("/:list_id", routing::get(mail::threads))
332- .route("/:list_id/:message_id", routing::get(mail::thread))
333- .route("/post/:list_id/:message_id", routing::get(mail::post))
334- .layer(from_fn_with_state(
335- Arc::new((cfg.clone(), templates.clone(), mail_required_plugins)),
336- rpc_initiator::required,
337- ))
338- .layer(from_fn_with_state(
339- Arc::new((cfg.clone(), templates.clone())),
340- template::middleware,
341- )),
342- )
343- .nest(
344- "/xmpp",
345- Router::new()
346- .route("/", routing::get(xmpp::channels))
347- .route("/:channel", routing::get(xmpp::channel))
348- .route("/:channel/:last_message", routing::get(xmpp::channel))
349- .layer(from_fn_with_state(
350- Arc::new((cfg.clone(), templates.clone(), xmpp_required_plugins)),
351- rpc_initiator::required,
352- ))
353- .layer(from_fn_with_state(
354- Arc::new((cfg.clone(), templates.clone())),
355- template::middleware,
356- )),
357- ),
358+ .layer(from_fn_with_state(
359+ Arc::new((cfg.clone(), templates.clone())),
360+ template::middleware,
361+ )),
362 )
363 .nest(
364 "/:collection/:name",
365 diff --git a/src/web2/util.rs b/src/web2/util.rs
366index 59de08c..79b1f3e 100644
367--- a/src/web2/util.rs
368+++ b/src/web2/util.rs
369 @@ -3,7 +3,6 @@ use std::path::PathBuf;
370 use axum::http::Uri;
371 use url::Url;
372
373-
374 // select a segment of the path from the given url between start and end.
375 // e.g.
376 // http://fuu.bar/baz/qux 0 1 -> Some(/baz)
377 @@ -60,7 +59,7 @@ pub mod navigation {
378
379 pub type Items = Vec<(String, String, bool)>;
380
381- pub fn global(current_page: &str, discuss_visible: bool) -> Items {
382+ pub fn global(current_page: &str, mail_visible: bool) -> Items {
383 let mut nav: Items = vec![
384 (
385 String::from("about"),
386 @@ -73,11 +72,11 @@ pub mod navigation {
387 current_page == "config",
388 ),
389 ];
390- if discuss_visible {
391+ if mail_visible {
392 nav.push((
393- String::from("discuss"),
394- String::from("/discuss"),
395- current_page == "discuss",
396+ String::from("mail"),
397+ String::from("/mail"),
398+ current_page == "mail",
399 ))
400 }
401 nav
402 @@ -193,26 +192,6 @@ pub mod navigation {
403 ),
404 ]
405 }
406-
407- pub fn discnav(current_page: &str) -> Items {
408- vec![
409- (
410- String::from("overview"),
411- String::from("/discuss"),
412- current_page == "overview",
413- ),
414- (
415- String::from("mail"),
416- String::from("/discuss/mail"),
417- current_page == "mail",
418- ),
419- (
420- String::from("xmpp"),
421- String::from("/discuss/xmpp"),
422- current_page == "xmpp",
423- ),
424- ]
425- }
426 }
427
428 const UNIT: f64 = 1024.0;
429 diff --git a/themes/default/templates/discuss.html b/themes/default/templates/discuss.html
430deleted file mode 100644
431index ae080ac..0000000
432--- a/themes/default/templates/discuss.html
433+++ /dev/null
434 @@ -1,11 +0,0 @@
435- {% import "macros.html" as macros %}
436- {% extends "base.html" %}
437- {% block content %}
438- <section>
439- <article>
440- <header>
441- {{ macros::navigation(items=discnav, title="Discussions") }}
442- </header>
443- </article>
444- </section>
445- {% endblock %}
446 diff --git a/themes/default/templates/lists.html b/themes/default/templates/lists.html
447index bdb32ba..0196b96 100644
448--- a/themes/default/templates/lists.html
449+++ b/themes/default/templates/lists.html
450 @@ -4,7 +4,7 @@
451 <section>
452 <article>
453 <header>
454- {{ macros::navigation(items=discnav, title="Mailing Lists") }}
455+ <h1> Mailing Lists </h1>
456 </header>
457 <table>
458 <thead>
459 @@ -16,9 +16,9 @@
460 <tbody>
461 {% for list in lists %}
462 <tr>
463- <td><a href="/discuss/mail/{{list.id}}">{{ list.id }}</a></td>
464+ <td>{{ list.id }}</td>
465 <td>{{ list.name }}</td>
466- <td>{{ list.description }}</td>
467+ <td><a href="/mail/{{list.id}}">{{ list.description }}</a></td>
468 <td>{{ list.address }}</td>
469 </tr>
470 {% endfor %}
471 diff --git a/themes/default/templates/thread.html b/themes/default/templates/thread.html
472index 764f9b7..d0005e8 100644
473--- a/themes/default/templates/thread.html
474+++ b/themes/default/templates/thread.html
475 @@ -7,7 +7,7 @@
476 <header>
477 <b>From: {{ reply.from_address }}</b></br>
478 <b>To: ???</b></br>
479- <b><a href="/discuss/mail/post/{{list_id}}/{{reply.message_id}}">{{ reply.message_id }}</a></b>
480+ <b><a href="/mail/{{list_id}}/message/{{reply.message_id}}">{{ reply.message_id }}</a></b>
481 <span class="right">{{ reply.created_at | format_epoch }}</span>
482 </header>
483 <pre>{{ reply.text }}</pre>
484 diff --git a/themes/default/templates/threads.html b/themes/default/templates/threads.html
485index d7c7431..c7f8cfb 100644
486--- a/themes/default/templates/threads.html
487+++ b/themes/default/templates/threads.html
488 @@ -4,8 +4,25 @@
489 <section>
490 <article>
491 <header>
492- {{ macros::navigation(items=discnav, title=list.id) }}
493+ <h1> {{ list.name }} </h1>
494 </header>
495+ <div class="mailing-list-details">
496+ <h4> {{ list.description }} </h4>
497+ </br>
498+ <span class="labels">
499+ {% for topic in list.topics %}
500+ <span class="feature">{{topic}}</span>
501+ {% endfor %}
502+ </br><b>Post Policy = {{list.post_policy}} </b>
503+ </br><b>Subscription Policy = {{list.subscription_policy.kind}}</b>
504+ </br><b>Send Confirmation = {{list.subscription_policy.send_confirmation}}</b>
505+ </br>
506+ </span></br>
507+ <h4> Subscribe </h4>
508+ <p> Send an e-mail to <a href="mailto:{{ request_email }}?subject=subscribe">{{request_email}}</a> with the following subject: <code>subscribe</code> </p>
509+ <h4> Unsubscribe </h4>
510+ <p> Send an e-mail to <a href="mailto:{{ request_email }}?subject=unsubscribe">{{request_email}}</a> with the following subject: <code>unsubscribe</code> </p>
511+ </div>
512 <table>
513 <thead>
514 <th> from </th>
515 @@ -18,7 +35,7 @@
516 <tr>
517 <td>{{ thread.from }}</a></td>
518 <td>{{thread.timestamp | format_epoch }}</td>
519- <td><a href="/discuss/mail/{{list.id}}/{{thread.message_id}}">{{thread.subject}}</a></td>
520+ <td><a href="/mail/{{list.id}}/thread/{{thread.message_id}}">{{thread.subject}}</a></td>
521 <td>{{thread.n_replies}}</td>
522 </tr>
523 {% endfor %}