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",
|
||||
"cookie",
|
||||
"envious",
|
||||
"futures-util",
|
||||
"jwt-simple",
|
||||
"once_cell",
|
||||
"openidconnect",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ base64 = "0.21.2"
|
|||
color-eyre = "0.6.2"
|
||||
cookie = "0.17.0"
|
||||
envious = "0.2.2"
|
||||
futures-util = "0.3.28"
|
||||
jwt-simple = "0.11.6"
|
||||
once_cell = "1.18.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 color_eyre::eyre;
|
||||
use cookie::{time::OffsetDateTime, SameSite};
|
||||
use futures_util::TryStreamExt;
|
||||
use jwt_simple::prelude::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use openidconnect::{
|
||||
|
|
@ -500,6 +501,17 @@ struct HomeQuery {
|
|||
user_error: Option<UserError>,
|
||||
}
|
||||
|
||||
struct AliasPart {
|
||||
mail: String,
|
||||
recipient: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Alias {
|
||||
mail: String,
|
||||
recipients: Vec<String>,
|
||||
}
|
||||
|
||||
async fn home(
|
||||
state: State<Arc<AppState>>,
|
||||
User(user): User,
|
||||
|
|
@ -513,9 +525,39 @@ async fn home(
|
|||
.fetch_all(&state.db)
|
||||
.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();
|
||||
context.insert("mails", &mails);
|
||||
context.insert("mail_domain", &state.mail_domain);
|
||||
context.insert("aliases", &aliases);
|
||||
if let Some(err) = query.user_error {
|
||||
tracing::info!("User error: {err:?}");
|
||||
context.insert("user_error", &err.to_string());
|
||||
|
|
|
|||
|
|
@ -81,13 +81,104 @@
|
|||
</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>
|
||||
<script>
|
||||
const addModal = document.getElementById('mailAdd')
|
||||
const addInput = document.getElementById('floatingAddMail')
|
||||
const addModal = document.getElementById('mailAdd');
|
||||
const addInput = document.getElementById('floatingAddMail');
|
||||
|
||||
addModal.addEventListener('shown.bs.modal', () => {
|
||||
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>
|
||||
{% endblock content %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue