4.25.1
This commit is contained in:
parent
3f68a3e640
commit
75331c62a4
@ -298,7 +298,9 @@ class HibpNotifiedAlias(Base, ModelMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
__tablename__ = "hibp_notified_alias"
|
__tablename__ = "hibp_notified_alias"
|
||||||
alias_id = sa.Column(sa.ForeignKey("alias.id", ondelete="cascade"), nullable=False)
|
alias_id = sa.Column(
|
||||||
|
sa.ForeignKey("alias.id", ondelete="cascade"), nullable=False, index=True
|
||||||
|
)
|
||||||
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=False)
|
user_id = sa.Column(sa.ForeignKey("users.id", ondelete="cascade"), nullable=False)
|
||||||
|
|
||||||
notified_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
notified_at = sa.Column(ArrowType, default=arrow.utcnow, nullable=False)
|
||||||
@ -426,7 +428,10 @@ class User(Base, ModelMixin, UserMixin, PasswordOracle):
|
|||||||
|
|
||||||
# newsletter is sent to this address
|
# newsletter is sent to this address
|
||||||
newsletter_alias_id = sa.Column(
|
newsletter_alias_id = sa.Column(
|
||||||
sa.ForeignKey("alias.id", ondelete="SET NULL"), nullable=True, default=None
|
sa.ForeignKey("alias.id", ondelete="SET NULL"),
|
||||||
|
nullable=True,
|
||||||
|
default=None,
|
||||||
|
index=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# whether to include the sender address in reverse-alias
|
# whether to include the sender address in reverse-alias
|
||||||
@ -1595,7 +1600,9 @@ class ClientUser(Base, ModelMixin):
|
|||||||
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False)
|
||||||
|
|
||||||
# Null means client has access to user original email
|
# Null means client has access to user original email
|
||||||
alias_id = sa.Column(sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=True)
|
alias_id = sa.Column(
|
||||||
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=True, index=True
|
||||||
|
)
|
||||||
|
|
||||||
# user can decide to send to client another name
|
# user can decide to send to client another name
|
||||||
name = sa.Column(
|
name = sa.Column(
|
||||||
@ -1714,7 +1721,7 @@ class Contact(Base, ModelMixin):
|
|||||||
is_cc = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
is_cc = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0")
|
||||||
|
|
||||||
pgp_public_key = sa.Column(sa.Text, nullable=True)
|
pgp_public_key = sa.Column(sa.Text, nullable=True)
|
||||||
pgp_finger_print = sa.Column(sa.String(512), nullable=True)
|
pgp_finger_print = sa.Column(sa.String(512), nullable=True, index=True)
|
||||||
|
|
||||||
alias = orm.relationship(Alias, backref="contacts")
|
alias = orm.relationship(Alias, backref="contacts")
|
||||||
user = orm.relationship(User)
|
user = orm.relationship(User)
|
||||||
@ -2125,7 +2132,9 @@ class AliasUsedOn(Base, ModelMixin):
|
|||||||
sa.UniqueConstraint("alias_id", "hostname", name="uq_alias_used"),
|
sa.UniqueConstraint("alias_id", "hostname", name="uq_alias_used"),
|
||||||
)
|
)
|
||||||
|
|
||||||
alias_id = sa.Column(sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=False)
|
alias_id = sa.Column(
|
||||||
|
sa.ForeignKey(Alias.id, ondelete="cascade"), nullable=False, index=True
|
||||||
|
)
|
||||||
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
user_id = sa.Column(sa.ForeignKey(User.id, ondelete="cascade"), nullable=False)
|
||||||
|
|
||||||
alias = orm.relationship(Alias)
|
alias = orm.relationship(Alias)
|
||||||
|
29
app/migrations/versions/2023_041418_893c0d18475f_.py
Normal file
29
app/migrations/versions/2023_041418_893c0d18475f_.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 893c0d18475f
|
||||||
|
Revises: 5f4a5625da66
|
||||||
|
Create Date: 2023-04-14 18:20:03.807367
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy_utils
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '893c0d18475f'
|
||||||
|
down_revision = '5f4a5625da66'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_index(op.f('ix_contact_pgp_finger_print'), 'contact', ['pgp_finger_print'], unique=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_index(op.f('ix_contact_pgp_finger_print'), table_name='contact')
|
||||||
|
# ### end Alembic commands ###
|
35
app/migrations/versions/2023_041419_bc496c0a0279_.py
Normal file
35
app/migrations/versions/2023_041419_bc496c0a0279_.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: bc496c0a0279
|
||||||
|
Revises: 893c0d18475f
|
||||||
|
Create Date: 2023-04-14 19:09:38.540514
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy_utils
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'bc496c0a0279'
|
||||||
|
down_revision = '893c0d18475f'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_index(op.f('ix_alias_used_on_alias_id'), 'alias_used_on', ['alias_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_client_user_alias_id'), 'client_user', ['alias_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_hibp_notified_alias_alias_id'), 'hibp_notified_alias', ['alias_id'], unique=False)
|
||||||
|
op.create_index(op.f('ix_users_newsletter_alias_id'), 'users', ['newsletter_alias_id'], unique=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_index(op.f('ix_users_newsletter_alias_id'), table_name='users')
|
||||||
|
op.drop_index(op.f('ix_hibp_notified_alias_alias_id'), table_name='hibp_notified_alias')
|
||||||
|
op.drop_index(op.f('ix_client_user_alias_id'), table_name='client_user')
|
||||||
|
op.drop_index(op.f('ix_alias_used_on_alias_id'), table_name='alias_used_on')
|
||||||
|
# ### end Alembic commands ###
|
@ -155,10 +155,8 @@ $(".pin-alias").change(async function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".save-note").on("click", async function () {
|
async function handleNoteChange(aliasId, aliasEmail) {
|
||||||
let oldValue;
|
const note = document.getElementById(`note-${aliasId}`).value;
|
||||||
let aliasId = $(this).data("alias");
|
|
||||||
let note = $(`#note-${aliasId}`).val();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
@ -172,26 +170,27 @@ $(".save-note").on("click", async function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toastr.success(`Saved`);
|
toastr.success(`Description saved for ${aliasEmail}`);
|
||||||
} else {
|
} else {
|
||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
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) {
|
} catch (e) {
|
||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
}
|
||||||
|
|
||||||
$(".save-mailbox").on("click", async function () {
|
function handleNoteFocus(aliasId) {
|
||||||
let oldValue;
|
document.getElementById(`note-focus-message-${aliasId}`).classList.remove('d-none');
|
||||||
let aliasId = $(this).data("alias");
|
}
|
||||||
let mailbox_ids = $(`#mailbox-${aliasId}`).val();
|
|
||||||
|
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) {
|
if (mailbox_ids.length === 0) {
|
||||||
toastr.error("You must select at least a mailbox", "Error");
|
toastr.error("You must select at least a mailbox", "Error");
|
||||||
@ -210,25 +209,18 @@ $(".save-mailbox").on("click", async function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toastr.success(`Mailbox Updated`);
|
toastr.success(`Mailbox updated for ${aliasEmail}`);
|
||||||
} else {
|
} else {
|
||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
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) {
|
} catch (e) {
|
||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
}
|
||||||
|
|
||||||
$(".save-alias-name").on("click", async function () {
|
async function handleDisplayNameChange(aliasId, aliasEmail) {
|
||||||
let aliasId = $(this).data("alias");
|
const name = document.getElementById(`alias-name-${aliasId}`).value;
|
||||||
let name = $(`#alias-name-${aliasId}`).val();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res = await fetch(`/api/aliases/${aliasId}`, {
|
let res = await fetch(`/api/aliases/${aliasId}`, {
|
||||||
@ -242,7 +234,7 @@ $(".save-alias-name").on("click", async function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
toastr.success(`Alias Name Saved`);
|
toastr.success(`Display name saved for ${aliasEmail}`);
|
||||||
} else {
|
} else {
|
||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
||||||
}
|
}
|
||||||
@ -250,8 +242,15 @@ $(".save-alias-name").on("click", async function () {
|
|||||||
toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error");
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#filter-app',
|
el: '#filter-app',
|
||||||
@ -270,4 +269,4 @@ new Vue({
|
|||||||
if (store.get("showFilter"))
|
if (store.get("showFilter"))
|
||||||
this.showFilter = true;
|
this.showFilter = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -342,17 +342,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- END Email Activity -->
|
<!-- END Email Activity -->
|
||||||
<div class="small-text mt-1">
|
<div class="small-text mt-1">
|
||||||
Alias description
|
Alias description <span id="note-focus-message-{{ alias.id }}" class="d-none font-italic">(automatically saved when you click outside the field)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex mb-2">
|
<div class="d-flex mb-2">
|
||||||
<div class="flex-grow-1 mr-2">
|
<div class="flex-grow-1 mr-2">
|
||||||
<textarea id="note-{{ alias.id }}" name="note" class="form-control" style="font-size: 12px" rows="2" placeholder="e.g. where the alias is used or why is it created">{{ alias.note or "" }}</textarea>
|
<textarea id="note-{{ alias.id }}" name="note" class="form-control" style="font-size: 12px" 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>
|
|
||||||
<div>
|
|
||||||
<a data-alias="{{ alias.id }}"
|
|
||||||
class="save-note btn btn-sm btn-outline-success w-100">
|
|
||||||
Save
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Send Email && More button -->
|
<!-- Send Email && More button -->
|
||||||
@ -421,7 +415,8 @@
|
|||||||
data-width="100%"
|
data-width="100%"
|
||||||
class="mailbox-select"
|
class="mailbox-select"
|
||||||
multiple
|
multiple
|
||||||
name="mailbox">
|
name="mailbox"
|
||||||
|
onchange="handleMailboxChange({{ alias.id }}, '{{ alias.email }}')">
|
||||||
{% for mailbox in mailboxes %}
|
{% for mailbox in mailboxes %}
|
||||||
|
|
||||||
<option value="{{ mailbox.id }}" {% if alias_info.contain_mailbox(mailbox.id) %}
|
<option value="{{ mailbox.id }}" {% if alias_info.contain_mailbox(mailbox.id) %}
|
||||||
@ -431,12 +426,6 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a data-alias="{{ alias.id }}"
|
|
||||||
class="save-mailbox btn btn-sm btn-outline-info w-100">
|
|
||||||
Update
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% elif alias_info.mailbox != None and alias_info.mailbox.email != current_user.email %}
|
{% elif alias_info.mailbox != None and alias_info.mailbox.email != current_user.email %}
|
||||||
<div class="small-text">
|
<div class="small-text">
|
||||||
@ -448,19 +437,18 @@
|
|||||||
title="When sending an email from this alias, the email will have 'Display Name <{{ alias.email }}>' as sender.">
|
title="When sending an email from this alias, the email will have 'Display Name <{{ alias.email }}>' as sender.">
|
||||||
Display name
|
Display name
|
||||||
<i class="fe fe-help-circle"></i>
|
<i class="fe fe-help-circle"></i>
|
||||||
|
<span id="display-name-focus-message-{{ alias.id }}"
|
||||||
|
class="d-none font-italic">(automatically saved when you click outside the field or press Enter)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="flex-grow-1 mr-2">
|
<div class="flex-grow-1 mr-2">
|
||||||
<input id="alias-name-{{ alias.id }}"
|
<input id="alias-name-{{ alias.id }}"
|
||||||
value="{{ alias.name or '' }}"
|
value="{{ alias.name or '' }}"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder="{{ alias.custom_domain.name or "Alias name" }}">
|
placeholder="{{ alias.custom_domain.name or "Alias name" }}"
|
||||||
</div>
|
onchange="handleDisplayNameChange({{ alias.id }}, '{{ alias.email }}')"
|
||||||
<div>
|
onfocus="handleDisplayNameFocus({{ alias.id }})"
|
||||||
<a data-alias="{{ alias.id }}"
|
onblur="handleDisplayNameBlur({{ alias.id }})">
|
||||||
class="save-alias-name btn btn-sm btn-outline-primary w-100">
|
|
||||||
Save
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if alias.mailbox_support_pgp() %}
|
{% if alias.mailbox_support_pgp() %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user