diff --git a/app/app/models.py b/app/app/models.py index e5b07ce..a46b967 100644 --- a/app/app/models.py +++ b/app/app/models.py @@ -298,7 +298,9 @@ class HibpNotifiedAlias(Base, ModelMixin): """ __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) 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_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 @@ -1595,7 +1600,9 @@ class ClientUser(Base, ModelMixin): client_id = sa.Column(sa.ForeignKey(Client.id, ondelete="cascade"), nullable=False) # 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 name = sa.Column( @@ -1714,7 +1721,7 @@ class Contact(Base, ModelMixin): is_cc = sa.Column(sa.Boolean, nullable=False, default=False, server_default="0") 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") user = orm.relationship(User) @@ -2125,7 +2132,9 @@ class AliasUsedOn(Base, ModelMixin): 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) alias = orm.relationship(Alias) diff --git a/app/migrations/versions/2023_041418_893c0d18475f_.py b/app/migrations/versions/2023_041418_893c0d18475f_.py new file mode 100644 index 0000000..bc3b08a --- /dev/null +++ b/app/migrations/versions/2023_041418_893c0d18475f_.py @@ -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 ### diff --git a/app/migrations/versions/2023_041419_bc496c0a0279_.py b/app/migrations/versions/2023_041419_bc496c0a0279_.py new file mode 100644 index 0000000..7f0e50d --- /dev/null +++ b/app/migrations/versions/2023_041419_bc496c0a0279_.py @@ -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 ### diff --git a/app/static/js/index.js b/app/static/js/index.js index 1cc87c4..3a55731 100644 --- a/app/static/js/index.js +++ b/app/static/js/index.js @@ -155,10 +155,8 @@ $(".pin-alias").change(async function () { } }); -$(".save-note").on("click", async function () { - let oldValue; - let aliasId = $(this).data("alias"); - let note = $(`#note-${aliasId}`).val(); +async function handleNoteChange(aliasId, aliasEmail) { + const note = document.getElementById(`note-${aliasId}`).value; try { let res = await fetch(`/api/aliases/${aliasId}`, { @@ -172,26 +170,27 @@ $(".save-note").on("click", async function () { }); if (res.ok) { - toastr.success(`Saved`); + toastr.success(`Description saved for ${aliasEmail}`); } 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); } -}); +} -$(".save-mailbox").on("click", async function () { - let oldValue; - let aliasId = $(this).data("alias"); - let mailbox_ids = $(`#mailbox-${aliasId}`).val(); +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"); @@ -210,25 +209,18 @@ $(".save-mailbox").on("click", async function () { }); if (res.ok) { - toastr.success(`Mailbox Updated`); + toastr.success(`Mailbox updated for ${aliasEmail}`); } 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); } -}); +} -$(".save-alias-name").on("click", async function () { - let aliasId = $(this).data("alias"); - let name = $(`#alias-name-${aliasId}`).val(); +async function handleDisplayNameChange(aliasId, aliasEmail) { + const name = document.getElementById(`alias-name-${aliasId}`).value; try { let res = await fetch(`/api/aliases/${aliasId}`, { @@ -242,7 +234,7 @@ $(".save-alias-name").on("click", async function () { }); if (res.ok) { - toastr.success(`Alias Name Saved`); + toastr.success(`Display name saved for ${aliasEmail}`); } else { 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"); } -}); +} +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({ el: '#filter-app', @@ -270,4 +269,4 @@ new Vue({ if (store.get("showFilter")) this.showFilter = true; } -}); \ No newline at end of file +}); diff --git a/app/templates/dashboard/index.html b/app/templates/dashboard/index.html index bdfa0b7..a3e24df 100644 --- a/app/templates/dashboard/index.html +++ b/app/templates/dashboard/index.html @@ -342,17 +342,11 @@