Display aliases
This commit is contained in:
parent
5cd7f26717
commit
1785d25bc6
4 changed files with 138 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1272,6 +1272,7 @@ dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"cookie",
|
"cookie",
|
||||||
"envious",
|
"envious",
|
||||||
|
"futures-util",
|
||||||
"jwt-simple",
|
"jwt-simple",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"openidconnect",
|
"openidconnect",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ base64 = "0.21.2"
|
||||||
color-eyre = "0.6.2"
|
color-eyre = "0.6.2"
|
||||||
cookie = "0.17.0"
|
cookie = "0.17.0"
|
||||||
envious = "0.2.2"
|
envious = "0.2.2"
|
||||||
|
futures-util = "0.3.28"
|
||||||
jwt-simple = "0.11.6"
|
jwt-simple = "0.11.6"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
openidconnect = "3.3.0"
|
openidconnect = "3.3.0"
|
||||||
|
|
|
||||||
42
src/main.rs
42
src/main.rs
|
|
@ -17,6 +17,7 @@ use axum_extra::extract::{cookie::Cookie, CookieJar};
|
||||||
use base64::{engine::general_purpose, engine::Engine};
|
use base64::{engine::general_purpose, engine::Engine};
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use cookie::{time::OffsetDateTime, SameSite};
|
use cookie::{time::OffsetDateTime, SameSite};
|
||||||
|
use futures_util::TryStreamExt;
|
||||||
use jwt_simple::prelude::*;
|
use jwt_simple::prelude::*;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use openidconnect::{
|
use openidconnect::{
|
||||||
|
|
@ -500,6 +501,17 @@ struct HomeQuery {
|
||||||
user_error: Option<UserError>,
|
user_error: Option<UserError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AliasPart {
|
||||||
|
mail: String,
|
||||||
|
recipient: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Alias {
|
||||||
|
mail: String,
|
||||||
|
recipients: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
async fn home(
|
async fn home(
|
||||||
state: State<Arc<AppState>>,
|
state: State<Arc<AppState>>,
|
||||||
User(user): User,
|
User(user): User,
|
||||||
|
|
@ -513,9 +525,39 @@ async fn home(
|
||||||
.fetch_all(&state.db)
|
.fetch_all(&state.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let aliases = sqlx::query_as!(
|
||||||
|
Mail,
|
||||||
|
"SELECT mail FROM emails WHERE id = $1 AND alias = true",
|
||||||
|
user
|
||||||
|
)
|
||||||
|
.fetch_all(&state.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut alias_stream = sqlx::query_as!(
|
||||||
|
AliasPart,
|
||||||
|
r#"
|
||||||
|
SELECT alias_recipient.mail,recipient
|
||||||
|
FROM emails,alias_recipient
|
||||||
|
WHERE id = $1 AND alias = true AND emails.mail = alias_recipient.mail
|
||||||
|
"#,
|
||||||
|
user
|
||||||
|
)
|
||||||
|
.fetch(&state.db);
|
||||||
|
|
||||||
|
let mut aliases: HashMap<_, _> = aliases.into_iter().map(|a| (a.mail, Vec::new())).collect();
|
||||||
|
while let Some(alias) = alias_stream.try_next().await? {
|
||||||
|
aliases.get_mut(&alias.mail).unwrap().push(alias.recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
let aliases: Vec<_> = aliases
|
||||||
|
.into_iter()
|
||||||
|
.map(|(mail, recipients)| Alias { mail, recipients })
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut context = tera::Context::new();
|
let mut context = tera::Context::new();
|
||||||
context.insert("mails", &mails);
|
context.insert("mails", &mails);
|
||||||
context.insert("mail_domain", &state.mail_domain);
|
context.insert("mail_domain", &state.mail_domain);
|
||||||
|
context.insert("aliases", &aliases);
|
||||||
if let Some(err) = query.user_error {
|
if let Some(err) = query.user_error {
|
||||||
tracing::info!("User error: {err:?}");
|
tracing::info!("User error: {err:?}");
|
||||||
context.insert("user_error", &err.to_string());
|
context.insert("user_error", &err.to_string());
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,104 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<h2 class="title is-2 mt-2">Aliases</h2>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for alias in aliases %}
|
||||||
|
<li class="list-group-item d-flex flex-column">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ alias.mail }}
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-danger"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#aliasDelete{{ loop.index }}">Delete</button>
|
||||||
|
<div class="modal fade"
|
||||||
|
tabindex="-1"
|
||||||
|
id="aliasDelete{{ loop.index }}"
|
||||||
|
aria-labelledby="aliasDeleteLabel{{ loop.index }}">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="aliasDeleteLabel{{ loop.index }}">Delete alias '{{ alias.mail }}'</h1>
|
||||||
|
<button type="button"
|
||||||
|
class="btn-close"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<form action="/alias/delete" method="post">
|
||||||
|
<input type="hidden" name="mail" value="{{ alias.mail }}" />
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group mt-1">
|
||||||
|
{% set alias_idx = loop.index %}
|
||||||
|
{% for recpt in alias.recipients %}<li class="list-group-item">{{ recpt }}</li>{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-primary mt-1 w-25"
|
||||||
|
data-bs-toggle="modal"
|
||||||
|
data-bs-target="#aliasRecptAdd{{ loop.index }}">Add Recipient</button>
|
||||||
|
<div class="modal fade"
|
||||||
|
tabindex="-1"
|
||||||
|
id="aliasRecptAdd{{ loop.index }}"
|
||||||
|
aria-labelledby="aliasRecptAddLabel{{ loop.index }}">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="aliasRecptAddLabel{{ loop.index }}">Add new recipient</h1>
|
||||||
|
<button type="button"
|
||||||
|
class="btn-close"
|
||||||
|
data-bs-dismiss="modal"
|
||||||
|
aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="/alias/recipient/add"
|
||||||
|
method="post"
|
||||||
|
id="aliasRecptAddForm{{ loop.index }}">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="email"
|
||||||
|
class="form-control"
|
||||||
|
id="floatingAddAliasRecpt{{ loop.index }}"
|
||||||
|
placeholder="mail@example.com"
|
||||||
|
name="recipient">
|
||||||
|
<label for="floatingAddAliasRecpt">Email address</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<input type="hidden" name="alias" value="{{ alias.mail }}" />
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit"
|
||||||
|
class="btn btn-primary"
|
||||||
|
form="aliasRecptAddForm{{ loop.index }}">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
const addModal = document.getElementById('mailAdd')
|
const addModal = document.getElementById('mailAdd');
|
||||||
const addInput = document.getElementById('floatingAddMail')
|
const addInput = document.getElementById('floatingAddMail');
|
||||||
|
|
||||||
addModal.addEventListener('shown.bs.modal', () => {
|
addModal.addEventListener('shown.bs.modal', () => {
|
||||||
addInput.focus()
|
addInput.focus()
|
||||||
})
|
});
|
||||||
|
|
||||||
|
{% for idx in range(start = 1, end=aliases | length + 1) %}
|
||||||
|
const addRecptModal{{ idx }} = document.getElementById('aliasRecptAdd{{ idx }}');
|
||||||
|
const addRecptInput{{ idx }} = document.getElementById('floatingAddAliasRecpt{{ idx }}');
|
||||||
|
|
||||||
|
addRecptModal{{ idx }}.addEventListener('shown.bs.modal', () => {
|
||||||
|
addRecptInput{{ idx }}.focus()
|
||||||
|
});
|
||||||
|
{% endfor %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue