Compare commits
8 Commits
d3fa437246
...
9f92fa5509
Author | SHA1 | Date |
---|---|---|
D-Bao | 9f92fa5509 | |
Son Nguyen Kim | 037bc9da36 | |
Son Nguyen Kim | ee0be3688f | |
D-Bao | f2418b5972 | |
D-Bao | aa235111a3 | |
D-Bao | 72a72a93b6 | |
D-Bao | f808d42240 | |
D-Bao | 4ff9dc80ba |
|
@ -5,6 +5,7 @@ from .views import (
|
||||||
custom_alias,
|
custom_alias,
|
||||||
subdomain,
|
subdomain,
|
||||||
billing,
|
billing,
|
||||||
|
alias_detail,
|
||||||
alias_log,
|
alias_log,
|
||||||
alias_export,
|
alias_export,
|
||||||
unsubscribe,
|
unsubscribe,
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
from flask import render_template, flash, redirect, url_for, request
|
||||||
|
from flask_login import login_required, current_user
|
||||||
|
|
||||||
|
from app import alias_utils
|
||||||
|
from app.api.serializer import get_alias_info_v3
|
||||||
|
from app.dashboard.base import dashboard_bp
|
||||||
|
from app.db import Session
|
||||||
|
from app.log import LOG
|
||||||
|
from app.utils import CSRFValidationForm
|
||||||
|
|
||||||
|
|
||||||
|
@dashboard_bp.route("/aliases/<int:alias_id>", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def aliases(alias_id):
|
||||||
|
alias_info = get_alias_info_v3(current_user, alias_id)
|
||||||
|
|
||||||
|
# sanity check
|
||||||
|
if not alias_info:
|
||||||
|
flash("You do not have access to this page", "warning")
|
||||||
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
|
alias = alias_info.alias
|
||||||
|
|
||||||
|
if alias.user_id != current_user.id:
|
||||||
|
flash("You do not have access to this page", "warning")
|
||||||
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
|
mailboxes = current_user.mailboxes()
|
||||||
|
|
||||||
|
csrf_form = CSRFValidationForm()
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if not csrf_form.validate():
|
||||||
|
flash("Invalid request", "warning")
|
||||||
|
return redirect(request.url)
|
||||||
|
if request.form.get("form-name") in ("delete-alias", "disable-alias"):
|
||||||
|
if request.form.get("form-name") == "delete-alias":
|
||||||
|
LOG.d("delete alias %s", alias)
|
||||||
|
email = alias.email
|
||||||
|
alias_utils.delete_alias(alias, current_user)
|
||||||
|
flash(f"Alias {email} has been deleted", "success")
|
||||||
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
|
elif request.form.get("form-name") == "disable-alias":
|
||||||
|
alias.enabled = False
|
||||||
|
Session.commit()
|
||||||
|
flash(f"Alias {alias.email} has been disabled", "success")
|
||||||
|
|
||||||
|
return redirect(url_for("dashboard.aliases", alias_id=alias.id))
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"dashboard/alias_detail.html",
|
||||||
|
alias_info=alias_info,
|
||||||
|
mailboxes=mailboxes,
|
||||||
|
csrf_form=csrf_form,
|
||||||
|
)
|
|
@ -162,7 +162,7 @@ def alias_transfer_receive_route():
|
||||||
Session.commit()
|
Session.commit()
|
||||||
|
|
||||||
flash(f"You are now owner of {alias.email}", "success")
|
flash(f"You are now owner of {alias.email}", "success")
|
||||||
return redirect(url_for("dashboard.index", highlight_alias_id=alias.id))
|
return redirect(url_for("dashboard.aliases", alias_id=alias.id))
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"dashboard/alias_transfer_receive.html",
|
"dashboard/alias_transfer_receive.html",
|
||||||
|
|
|
@ -11,9 +11,11 @@ from wtforms.fields.html5 import EmailField
|
||||||
from app.config import ENFORCE_SPF, MAILBOX_SECRET
|
from app.config import ENFORCE_SPF, MAILBOX_SECRET
|
||||||
from app.config import URL
|
from app.config import URL
|
||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
|
from app.dashboard.views.enter_sudo import sudo_required
|
||||||
from app.db import Session
|
from app.db import Session
|
||||||
from app.email_utils import email_can_be_used_as_mailbox
|
from app.email_utils import email_can_be_used_as_mailbox
|
||||||
from app.email_utils import mailbox_already_used, render, send_email
|
from app.email_utils import mailbox_already_used, render, send_email
|
||||||
|
from app.extensions import limiter
|
||||||
from app.log import LOG
|
from app.log import LOG
|
||||||
from app.models import Alias, AuthorizedAddress
|
from app.models import Alias, AuthorizedAddress
|
||||||
from app.models import Mailbox
|
from app.models import Mailbox
|
||||||
|
@ -29,6 +31,8 @@ class ChangeEmailForm(FlaskForm):
|
||||||
|
|
||||||
@dashboard_bp.route("/mailbox/<int:mailbox_id>/", methods=["GET", "POST"])
|
@dashboard_bp.route("/mailbox/<int:mailbox_id>/", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
|
@sudo_required
|
||||||
|
@limiter.limit("20/minute", methods=["POST"])
|
||||||
def mailbox_detail_route(mailbox_id):
|
def mailbox_detail_route(mailbox_id):
|
||||||
mailbox: Mailbox = Mailbox.get(mailbox_id)
|
mailbox: Mailbox = Mailbox.get(mailbox_id)
|
||||||
if not mailbox or mailbox.user_id != current_user.id:
|
if not mailbox or mailbox.user_id != current_user.id:
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
$('.mailbox-select').multipleSelect();
|
||||||
|
|
||||||
|
function confirmDeleteAlias() {
|
||||||
|
let that = $(this);
|
||||||
|
let alias = that.data("alias-email");
|
||||||
|
let aliasDomainTrashUrl = that.data("custom-domain-trash-url");
|
||||||
|
|
||||||
|
let message = `Maybe you want to disable the alias instead? Please note once deleted, it <b>can't</b> be restored.`;
|
||||||
|
if (aliasDomainTrashUrl !== undefined) {
|
||||||
|
message = `Maybe you want to disable the alias instead? When it's deleted, it's moved to the domain
|
||||||
|
<a href="${aliasDomainTrashUrl}">trash</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootbox.dialog({
|
||||||
|
title: `Delete ${alias}`,
|
||||||
|
message: message,
|
||||||
|
size: 'large',
|
||||||
|
onEscape: true,
|
||||||
|
backdrop: true,
|
||||||
|
buttons: {
|
||||||
|
disable: {
|
||||||
|
label: 'Disable it',
|
||||||
|
className: 'btn-primary',
|
||||||
|
callback: function () {
|
||||||
|
that.closest("form").find('input[name="form-name"]').val("disable-alias");
|
||||||
|
that.closest("form").submit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
delete: {
|
||||||
|
label: "Delete it, I don't need it anymore",
|
||||||
|
className: 'btn-outline-danger',
|
||||||
|
callback: function () {
|
||||||
|
that.closest("form").submit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: {
|
||||||
|
label: 'Cancel',
|
||||||
|
className: 'btn-outline-primary'
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".enable-disable-alias").change(async function () {
|
||||||
|
let aliasId = $(this).data("alias");
|
||||||
|
let alias = $(this).data("alias-email");
|
||||||
|
|
||||||
|
await disableAlias(aliasId, alias);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function disableAlias(aliasId, alias) {
|
||||||
|
let oldValue;
|
||||||
|
try {
|
||||||
|
let res = await fetch(`/api/aliases/${aliasId}/toggle`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
let json = await res.json();
|
||||||
|
|
||||||
|
if (json.enabled) {
|
||||||
|
toastr.success(`${alias} is enabled`);
|
||||||
|
$(`#send-email-${aliasId}`).removeClass("disabled");
|
||||||
|
} else {
|
||||||
|
toastr.success(`${alias} is disabled`);
|
||||||
|
$(`#send-email-${aliasId}`).addClass("disabled");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
// reset to the original value
|
||||||
|
oldValue = !$(this).prop("checked");
|
||||||
|
$(this).prop("checked", oldValue);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
// reset to the original value
|
||||||
|
oldValue = !$(this).prop("checked");
|
||||||
|
$(this).prop("checked", oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".enable-disable-pgp").change(async function (e) {
|
||||||
|
let aliasId = $(this).data("alias");
|
||||||
|
let alias = $(this).data("alias-email");
|
||||||
|
const oldValue = !$(this).prop("checked");
|
||||||
|
let newValue = !oldValue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
disable_pgp: oldValue,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
if (newValue) {
|
||||||
|
toastr.success(`PGP is enabled for ${alias}`);
|
||||||
|
} else {
|
||||||
|
toastr.info(`PGP is disabled for ${alias}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
// reset to the original value
|
||||||
|
$(this).prop("checked", oldValue);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
// reset to the original value
|
||||||
|
$(this).prop("checked", oldValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleNoteChange(aliasId, aliasEmail) {
|
||||||
|
const note = document.getElementById(`note-${aliasId}`).value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
note: note,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
toastr.success(`Description saved for ${aliasEmail}`);
|
||||||
|
} else {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNoteFocus(aliasId) {
|
||||||
|
document.getElementById(`note-focus-message-${aliasId}`).classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNoteBlur(aliasId) {
|
||||||
|
document.getElementById(`note-focus-message-${aliasId}`).classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleMailboxChange(aliasId, aliasEmail) {
|
||||||
|
const selectedOptions = document.getElementById(`mailbox-${aliasId}`).selectedOptions;
|
||||||
|
const mailbox_ids = Array.from(selectedOptions).map((selectedOption) => selectedOption.value);
|
||||||
|
|
||||||
|
if (mailbox_ids.length === 0) {
|
||||||
|
toastr.error("You must select at least a mailbox", "Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
mailbox_ids: mailbox_ids,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
toastr.success(`Mailbox updated for ${aliasEmail}`);
|
||||||
|
} else {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDisplayNameChange(aliasId, aliasEmail) {
|
||||||
|
const name = document.getElementById(`alias-name-${aliasId}`).value;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: name,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
toastr.success(`Display name saved for ${aliasEmail}`);
|
||||||
|
} else {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDisplayNameFocus(aliasId) {
|
||||||
|
document.getElementById(`display-name-focus-message-${aliasId}`).classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDisplayNameBlur(aliasId) {
|
||||||
|
document.getElementById(`display-name-focus-message-${aliasId}`).classList.add('d-none');
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
{% extends "default.html" %}
|
||||||
|
|
||||||
|
{% set active_page = "dashboard" %}
|
||||||
|
{% block title %}Alias Detail{% endblock %}
|
||||||
|
{% block default_content %}
|
||||||
|
|
||||||
|
{% set alias = alias_info.alias %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-3 order-lg-1 mb-4">
|
||||||
|
<!-- side panel here for alias log and contact manager in the future -->
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="clipboard cursor d-inline-block text-break"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Click to copy"
|
||||||
|
data-clipboard-text="{{ alias.email }}">
|
||||||
|
{{ alias.email }}
|
||||||
|
</h3>
|
||||||
|
{% if alias.automatic_creation %}
|
||||||
|
|
||||||
|
<p class="mb-0">
|
||||||
|
<span class="fa fa-inbox" data-toggle="tooltip" title=""></span> Alias automatically generated because of an incoming email
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if alias.hibp_breaches | length > 0 %}
|
||||||
|
|
||||||
|
<p class="mb-0">
|
||||||
|
<span class="fa fa-warning text-danger" data-toggle="tooltip" title=""></span> Found in {{ alias.hibp_breaches | length }} data breaches. <a href="https://haveibeenpwned.com/account/{{ alias.email }}">Check haveibeenpwned.com for more information <span class="fa fa-external-link"></span>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if alias.custom_domain and not alias.custom_domain.verified %}
|
||||||
|
|
||||||
|
<p class="">
|
||||||
|
<span class="fa fa-warning text-warning" data-toggle="tooltip" title=""></span> Cannot receive emails as the domain doesn't have MX records set up
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<!-- Email Activity -->
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col">
|
||||||
|
<div class="small-text">
|
||||||
|
{% if alias_info.latest_email_log != None %}
|
||||||
|
|
||||||
|
{% set email_log = alias_info.latest_email_log %}
|
||||||
|
{% set contact = alias_info.latest_contact %}
|
||||||
|
{% if email_log.is_reply %}
|
||||||
|
|
||||||
|
{{ contact.website_email }}
|
||||||
|
<i class="fa fa-reply mr-2"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Email reply/sent from alias"></i>
|
||||||
|
{{ email_log.created_at | dt }}
|
||||||
|
{% elif email_log.bounced %}
|
||||||
|
<span class="text-danger">
|
||||||
|
{{ contact.website_email }}
|
||||||
|
<i class="fa fa-warning mr-2"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Email bounced and cannot be forwarded to your mailbox"></i>
|
||||||
|
{{ email_log.created_at | dt }}
|
||||||
|
</span>
|
||||||
|
{% elif email_log.blocked %}
|
||||||
|
{{ contact.website_email }}
|
||||||
|
<i class="fa fa-ban mr-2 text-danger"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Email blocked"></i>
|
||||||
|
{{ email_log.created_at | dt }}
|
||||||
|
{% else %}
|
||||||
|
{{ contact.website_email }}
|
||||||
|
<i class="fa fa-paper-plane mr-2"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Email sent to alias"></i>
|
||||||
|
{{ email_log.created_at | dt }}
|
||||||
|
{% include 'partials/toggle_contact.html' %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
No emails received/sent in the last 14 days. Created {{ alias.created_at | dt }}.
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END Email Activity -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="mb-0" for="note-{{ alias.id }}">
|
||||||
|
Alias description <span id="note-focus-message-{{ alias.id }}"
|
||||||
|
class="d-none small-text font-italic">(automatically saved when you click outside the field)</span>
|
||||||
|
</label>
|
||||||
|
<textarea id="note-{{ alias.id }}" name="note" class="form-control" rows="2" placeholder="e.g. where the alias is used or why is it created" onchange="handleNoteChange({{ alias.id }}, '{{ alias.email }}')" onfocus="handleNoteFocus({{ alias.id }})" onblur="handleNoteBlur({{ alias.id }})">{{ alias.note or "" }}</textarea>
|
||||||
|
</div>
|
||||||
|
{% if mailboxes|length > 1 %}
|
||||||
|
|
||||||
|
<label class="mb-0" for="mailbox-{{ alias.id }}">Current mailbox</label>
|
||||||
|
<select required
|
||||||
|
id="mailbox-{{ alias.id }}"
|
||||||
|
data-width="100%"
|
||||||
|
class="mailbox-select mb-4"
|
||||||
|
multiple
|
||||||
|
name="mailbox"
|
||||||
|
onchange="handleMailboxChange({{ alias.id }}, '{{ alias.email }}')">
|
||||||
|
{% for mailbox in mailboxes %}
|
||||||
|
|
||||||
|
<option value="{{ mailbox.id }}" {% if alias_info.contain_mailbox(mailbox.id) %}
|
||||||
|
selected {% endif %}>
|
||||||
|
{{ mailbox.email }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
{% elif alias_info.mailbox != None and alias_info.mailbox.email != current_user.email %}
|
||||||
|
<div class="small-text mb-4">
|
||||||
|
Owned by <b>{{ alias_info.mailbox.email }}</b> mailbox
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="mb-0" for="alias-name-{{ alias.id }}">Display name</label>
|
||||||
|
<span id="display-name-focus-message-{{ alias.id }}"
|
||||||
|
class="d-none small-text font-italic">(automatically saved when you click outside the field or press Enter)</span>
|
||||||
|
<div class="small-text">
|
||||||
|
When sending an email from this alias, the email will have '{{ alias.name or "Your Display Name" }} <{{ alias.email }}>' as sender.
|
||||||
|
</div>
|
||||||
|
<input id="alias-name-{{ alias.id }}"
|
||||||
|
value="{{ alias.name or '' }}"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="{{ alias.custom_domain.name or "Alias name" }}"
|
||||||
|
onchange="handleDisplayNameChange({{ alias.id }}, '{{ alias.email }}')"
|
||||||
|
onfocus="handleDisplayNameFocus({{ alias.id }})"
|
||||||
|
onblur="handleDisplayNameBlur({{ alias.id }})">
|
||||||
|
</div>
|
||||||
|
{% if alias.mailbox_support_pgp() %}
|
||||||
|
|
||||||
|
<div class="d-flex align-items-start mb-4">
|
||||||
|
<label class="custom-switch cursor pl-0 mt-1">
|
||||||
|
<input id="enable-disable-pgp-{{ alias.id }}" type="checkbox" class="enable-disable-pgp custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.pgp_enabled() else "" }}>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
</label>
|
||||||
|
<label for="enable-disable-pgp-{{ alias.id }}" class="ml-2">
|
||||||
|
PGP
|
||||||
|
<br>
|
||||||
|
<span class="small-text">It can be useful to disable PGP if the sender already encrypts the emails</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="d-flex align-items-start mb-4">
|
||||||
|
<label class="custom-switch cursor pl-0 mt-1">
|
||||||
|
<input type="checkbox" id="enable-disable-alias-{{ alias.id }}" class="enable-disable-alias custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.enabled else "" }}>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
</label>
|
||||||
|
<label for="enable-disable-alias-{{ alias.id }}" class="ml-2">
|
||||||
|
Alias enabled
|
||||||
|
<br>
|
||||||
|
<span class="small-text">{{ "To stop receiving emails sent to this alias, you can disable the alias." if alias.enabled else "Enable the alias to start receiving emails sent to this alias." }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
{% if alias_info.latest_email_log != None %}<div>Alias created {{ alias.created_at | dt }}</div>{% endif %}
|
||||||
|
<span class="alias-activity">{{ alias_info.nb_forward }}</span> forwarded,
|
||||||
|
<span class="alias-activity">{{ alias_info.nb_blocked }}</span> blocked,
|
||||||
|
<span class="alias-activity">{{ alias_info.nb_reply }}</span> sent
|
||||||
|
in the last 14 days
|
||||||
|
<a href="{{ url_for('dashboard.alias_log', alias_id=alias.id) }}"
|
||||||
|
class="btn btn-sm btn-link">See All →</a>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="mr-auto">
|
||||||
|
<a href="{{ url_for('dashboard.alias_contact_manager', alias_id=alias.id) }}"
|
||||||
|
id="send-email-{{ alias.id }}"
|
||||||
|
class="btn btn-sm btn-outline-primary {% if not alias.enabled %}disabled{% endif %} "
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="Add new contact, manage your existing contacts">
|
||||||
|
Contacts <i class="fe fe-send"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group ml-auto" role="group" aria-label="Basic example">
|
||||||
|
<a href="{{ url_for('dashboard.alias_transfer_send_route', alias_id=alias.id) }}"
|
||||||
|
class="btn btn-sm btn-link">
|
||||||
|
Transfer
|
||||||
|
<i class="ml-0 dropdown-icon fe fe-share-2 text-primary"></i>
|
||||||
|
</a>
|
||||||
|
<form method="post">
|
||||||
|
{{ csrf_form.csrf_token }}
|
||||||
|
<input type="hidden" name="form-name" value="delete-alias">
|
||||||
|
<input type="hidden" name="alias-id" value="{{ alias.id }}">
|
||||||
|
<input type="hidden" name="alias" class="alias" value="{{ alias.email }}">
|
||||||
|
<span class="btn btn-link btn-sm float-right text-danger"
|
||||||
|
onclick="confirmDeleteAlias.call(this)"
|
||||||
|
{% if alias.custom_domain %} data-custom-domain-trash-url="{{ alias.custom_domain.get_trash_url() }}"{% endif %}
|
||||||
|
data-alias="{{ alias.id }}"
|
||||||
|
data-alias-email="{{ alias.email }}">
|
||||||
|
Delete
|
||||||
|
<i class="ml-0 dropdown-icon fe fe-trash-2 text-danger"></i>
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block script %}<script src="/static/js/alias-detail.js"></script>{% endblock %}
|
|
@ -68,7 +68,7 @@
|
||||||
<br />
|
<br />
|
||||||
<span>
|
<span>
|
||||||
To: {{ alias.email }}
|
To: {{ alias.email }}
|
||||||
<a href='{{ url_for("dashboard.index", highlight_alias_id=alias.id) }}'
|
<a href='{{ url_for("dashboard.aliases", alias_id=alias.id) }}'
|
||||||
class="text-danger small-text"
|
class="text-danger small-text"
|
||||||
style="text-decoration: underline">
|
style="text-decoration: underline">
|
||||||
Disable Alias
|
Disable Alias
|
||||||
|
|
Loading…
Reference in New Issue