2020-04-05 14:32:38 +00:00
|
|
|
from dataclasses import dataclass
|
|
|
|
|
2020-04-06 20:26:35 +00:00
|
|
|
from arrow import Arrow
|
2020-08-21 17:51:48 +00:00
|
|
|
from sqlalchemy import or_, func, case, and_
|
2020-04-25 09:14:17 +00:00
|
|
|
from sqlalchemy.orm import joinedload
|
2020-04-05 14:32:38 +00:00
|
|
|
|
|
|
|
from app.config import PAGE_LIMIT
|
|
|
|
from app.extensions import db
|
2020-08-29 17:03:33 +00:00
|
|
|
from app.models import Alias, Contact, EmailLog, Mailbox, AliasMailbox
|
2020-04-05 14:32:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class AliasInfo:
|
|
|
|
alias: Alias
|
2020-04-25 09:14:17 +00:00
|
|
|
mailbox: Mailbox
|
2020-05-03 13:56:45 +00:00
|
|
|
mailboxes: [Mailbox]
|
2020-04-05 14:32:38 +00:00
|
|
|
|
|
|
|
nb_forward: int
|
|
|
|
nb_blocked: int
|
|
|
|
nb_reply: int
|
|
|
|
|
2020-04-06 20:26:35 +00:00
|
|
|
latest_email_log: EmailLog = None
|
|
|
|
latest_contact: Contact = None
|
|
|
|
|
2020-05-03 13:56:45 +00:00
|
|
|
def contain_mailbox(self, mailbox_id: int) -> bool:
|
|
|
|
return mailbox_id in [m.id for m in self.mailboxes]
|
|
|
|
|
2020-04-05 14:32:38 +00:00
|
|
|
|
|
|
|
def serialize_alias_info(alias_info: AliasInfo) -> dict:
|
|
|
|
return {
|
|
|
|
# Alias field
|
|
|
|
"id": alias_info.alias.id,
|
|
|
|
"email": alias_info.alias.email,
|
|
|
|
"creation_date": alias_info.alias.created_at.format(),
|
|
|
|
"creation_timestamp": alias_info.alias.created_at.timestamp,
|
|
|
|
"enabled": alias_info.alias.enabled,
|
|
|
|
"note": alias_info.alias.note,
|
|
|
|
# activity
|
|
|
|
"nb_forward": alias_info.nb_forward,
|
|
|
|
"nb_block": alias_info.nb_blocked,
|
|
|
|
"nb_reply": alias_info.nb_reply,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-06 20:26:35 +00:00
|
|
|
def serialize_alias_info_v2(alias_info: AliasInfo) -> dict:
|
|
|
|
res = {
|
|
|
|
# Alias field
|
|
|
|
"id": alias_info.alias.id,
|
|
|
|
"email": alias_info.alias.email,
|
|
|
|
"creation_date": alias_info.alias.created_at.format(),
|
|
|
|
"creation_timestamp": alias_info.alias.created_at.timestamp,
|
|
|
|
"enabled": alias_info.alias.enabled,
|
|
|
|
"note": alias_info.alias.note,
|
2020-04-26 08:38:58 +00:00
|
|
|
"name": alias_info.alias.name,
|
2020-04-06 20:26:35 +00:00
|
|
|
# activity
|
|
|
|
"nb_forward": alias_info.nb_forward,
|
|
|
|
"nb_block": alias_info.nb_blocked,
|
|
|
|
"nb_reply": alias_info.nb_reply,
|
2020-04-25 21:13:05 +00:00
|
|
|
# mailbox
|
2020-04-25 21:40:40 +00:00
|
|
|
"mailbox": {"id": alias_info.mailbox.id, "email": alias_info.mailbox.email},
|
2020-05-03 13:56:45 +00:00
|
|
|
"mailboxes": [
|
|
|
|
{"id": mailbox.id, "email": mailbox.email}
|
|
|
|
for mailbox in alias_info.mailboxes
|
|
|
|
],
|
2020-08-04 18:11:59 +00:00
|
|
|
"support_pgp": alias_info.alias.mailbox_support_pgp(),
|
2020-08-06 12:22:28 +00:00
|
|
|
"disable_pgp": alias_info.alias.disable_pgp,
|
2020-11-01 11:32:20 +00:00
|
|
|
"latest_activity": None,
|
2020-04-06 20:26:35 +00:00
|
|
|
}
|
|
|
|
if alias_info.latest_email_log:
|
|
|
|
email_log = alias_info.latest_email_log
|
|
|
|
contact = alias_info.latest_contact
|
|
|
|
# latest activity
|
|
|
|
res["latest_activity"] = {
|
|
|
|
"timestamp": email_log.created_at.timestamp,
|
|
|
|
"action": email_log.get_action(),
|
|
|
|
"contact": {
|
|
|
|
"email": contact.website_email,
|
|
|
|
"name": contact.name,
|
|
|
|
"reverse_alias": contact.website_send_to(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
2020-04-05 14:32:38 +00:00
|
|
|
def serialize_contact(contact: Contact) -> dict:
|
|
|
|
res = {
|
|
|
|
"id": contact.id,
|
|
|
|
"creation_date": contact.created_at.format(),
|
|
|
|
"creation_timestamp": contact.created_at.timestamp,
|
|
|
|
"last_email_sent_date": None,
|
|
|
|
"last_email_sent_timestamp": None,
|
|
|
|
"contact": contact.website_email,
|
|
|
|
"reverse_alias": contact.website_send_to(),
|
|
|
|
}
|
|
|
|
|
|
|
|
email_log: EmailLog = contact.last_reply()
|
|
|
|
if email_log:
|
|
|
|
res["last_email_sent_date"] = email_log.created_at.format()
|
|
|
|
res["last_email_sent_timestamp"] = email_log.created_at.timestamp
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
def get_alias_infos_with_pagination(user, page_id=0, query=None) -> [AliasInfo]:
|
|
|
|
ret = []
|
|
|
|
q = (
|
|
|
|
db.session.query(Alias)
|
2020-04-25 09:14:17 +00:00
|
|
|
.options(joinedload(Alias.mailbox))
|
2020-04-05 14:32:38 +00:00
|
|
|
.filter(Alias.user_id == user.id)
|
|
|
|
.order_by(Alias.created_at.desc())
|
|
|
|
)
|
|
|
|
|
|
|
|
if query:
|
|
|
|
q = q.filter(
|
|
|
|
or_(Alias.email.ilike(f"%{query}%"), Alias.note.ilike(f"%{query}%"))
|
|
|
|
)
|
|
|
|
|
|
|
|
q = q.limit(PAGE_LIMIT).offset(page_id * PAGE_LIMIT)
|
|
|
|
|
|
|
|
for alias in q:
|
|
|
|
ret.append(get_alias_info(alias))
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2020-04-25 10:46:20 +00:00
|
|
|
def get_alias_infos_with_pagination_v2(
|
2020-04-26 11:04:27 +00:00
|
|
|
user, page_id=0, query=None, sort=None, alias_filter=None
|
2020-04-25 10:46:20 +00:00
|
|
|
) -> [AliasInfo]:
|
2020-04-06 20:26:35 +00:00
|
|
|
ret = []
|
|
|
|
latest_activity = func.max(
|
|
|
|
case(
|
|
|
|
[
|
|
|
|
(Alias.created_at > EmailLog.created_at, Alias.created_at),
|
|
|
|
(Alias.created_at < EmailLog.created_at, EmailLog.created_at),
|
|
|
|
],
|
|
|
|
else_=Alias.created_at,
|
|
|
|
)
|
|
|
|
).label("latest")
|
|
|
|
|
|
|
|
q = (
|
2020-04-25 10:46:20 +00:00
|
|
|
db.session.query(Alias, Mailbox, latest_activity)
|
2020-04-06 20:26:35 +00:00
|
|
|
.join(Contact, Alias.id == Contact.alias_id, isouter=True)
|
|
|
|
.join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True)
|
|
|
|
.filter(Alias.user_id == user.id)
|
2020-04-25 10:46:20 +00:00
|
|
|
.filter(Alias.mailbox_id == Mailbox.id)
|
2020-04-06 20:26:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if query:
|
|
|
|
q = q.filter(
|
2020-08-07 07:56:44 +00:00
|
|
|
or_(
|
|
|
|
Alias.email.ilike(f"%{query}%"),
|
|
|
|
Alias.note.ilike(f"%{query}%"),
|
|
|
|
Alias.name.ilike(f"%{query}%"),
|
|
|
|
)
|
2020-04-06 20:26:35 +00:00
|
|
|
)
|
|
|
|
|
2020-04-26 11:04:27 +00:00
|
|
|
if alias_filter == "enabled":
|
2020-04-26 10:31:10 +00:00
|
|
|
q = q.filter(Alias.enabled)
|
2020-04-26 11:04:27 +00:00
|
|
|
elif alias_filter == "disabled":
|
|
|
|
q = q.filter(Alias.enabled == False)
|
2020-04-26 10:31:10 +00:00
|
|
|
|
2020-04-25 10:46:20 +00:00
|
|
|
if sort == "old2new":
|
|
|
|
q = q.order_by(Alias.created_at)
|
2020-04-26 10:25:12 +00:00
|
|
|
elif sort == "new2old":
|
|
|
|
q = q.order_by(Alias.created_at.desc())
|
|
|
|
elif sort == "a2z":
|
|
|
|
q = q.order_by(Alias.email)
|
|
|
|
elif sort == "z2a":
|
|
|
|
q = q.order_by(Alias.email.desc())
|
2020-04-25 10:46:20 +00:00
|
|
|
else:
|
|
|
|
# default sorting
|
|
|
|
q = q.order_by(latest_activity.desc())
|
|
|
|
|
|
|
|
q = q.group_by(Alias.id, Mailbox.id)
|
|
|
|
|
2020-05-03 13:56:45 +00:00
|
|
|
q = list(q.limit(PAGE_LIMIT).offset(page_id * PAGE_LIMIT))
|
|
|
|
|
|
|
|
# preload alias.mailboxes to speed up
|
|
|
|
alias_ids = [alias.id for alias, _, _ in q]
|
|
|
|
Alias.query.options(joinedload(Alias._mailboxes)).filter(
|
|
|
|
Alias.id.in_(alias_ids)
|
|
|
|
).all()
|
2020-04-06 20:26:35 +00:00
|
|
|
|
2020-04-25 10:46:20 +00:00
|
|
|
for alias, mailbox, latest_activity in q:
|
|
|
|
ret.append(get_alias_info_v2(alias, mailbox))
|
2020-04-06 20:26:35 +00:00
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2020-08-21 17:51:48 +00:00
|
|
|
def get_alias_infos_with_pagination_v3(
|
|
|
|
user, page_id=0, query=None, sort=None, alias_filter=None
|
|
|
|
) -> [AliasInfo]:
|
|
|
|
sub = (
|
|
|
|
db.session.query(
|
|
|
|
Alias.id,
|
|
|
|
func.sum(case([(EmailLog.is_reply, 1)], else_=0)).label("nb_reply"),
|
|
|
|
func.sum(
|
|
|
|
case(
|
2020-08-27 08:20:48 +00:00
|
|
|
[(and_(EmailLog.is_reply == False, EmailLog.blocked), 1)],
|
|
|
|
else_=0,
|
2020-08-21 17:51:48 +00:00
|
|
|
)
|
|
|
|
).label("nb_blocked"),
|
|
|
|
func.sum(
|
|
|
|
case(
|
|
|
|
[
|
|
|
|
(
|
|
|
|
and_(
|
2020-08-27 08:20:48 +00:00
|
|
|
EmailLog.is_reply == False,
|
|
|
|
EmailLog.blocked == False,
|
2020-08-21 17:51:48 +00:00
|
|
|
),
|
|
|
|
1,
|
|
|
|
)
|
|
|
|
],
|
|
|
|
else_=0,
|
|
|
|
)
|
|
|
|
).label("nb_forward"),
|
|
|
|
func.max(EmailLog.created_at).label("max_created_at"),
|
|
|
|
)
|
|
|
|
.join(Contact, Alias.id == Contact.alias_id, isouter=True)
|
|
|
|
.join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True)
|
|
|
|
.filter(Alias.user_id == user.id)
|
|
|
|
.group_by(Alias.id)
|
|
|
|
.subquery()
|
|
|
|
)
|
|
|
|
|
2020-11-01 11:24:19 +00:00
|
|
|
if query:
|
2020-11-03 14:10:57 +00:00
|
|
|
mailboxes_sub = (
|
|
|
|
db.session.query(
|
|
|
|
Alias.id,
|
|
|
|
func.count(Mailbox.id).label("nb_matched_mailboxes"),
|
|
|
|
)
|
|
|
|
.join(AliasMailbox, Alias.id == AliasMailbox.alias_id, isouter=True)
|
|
|
|
.join(
|
|
|
|
Mailbox,
|
|
|
|
and_(
|
|
|
|
AliasMailbox.mailbox_id == Mailbox.id,
|
|
|
|
Mailbox.email.ilike(f"%{query}%"),
|
|
|
|
),
|
|
|
|
isouter=True,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
mailboxes_sub = (
|
|
|
|
db.session.query(
|
|
|
|
Alias.id,
|
|
|
|
func.count(Mailbox.id).label("nb_matched_mailboxes"),
|
|
|
|
)
|
|
|
|
.join(AliasMailbox, Alias.id == AliasMailbox.alias_id, isouter=True)
|
|
|
|
.join(Mailbox, AliasMailbox.mailbox_id == Mailbox.id, isouter=True)
|
2020-11-01 11:24:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
mailboxes_sub = mailboxes_sub.group_by(Alias.id).subquery()
|
|
|
|
|
2020-08-21 21:10:23 +00:00
|
|
|
latest_activity = case(
|
|
|
|
[
|
|
|
|
(Alias.created_at > EmailLog.created_at, Alias.created_at),
|
|
|
|
(Alias.created_at < EmailLog.created_at, EmailLog.created_at),
|
|
|
|
],
|
|
|
|
else_=Alias.created_at,
|
|
|
|
)
|
|
|
|
|
2020-08-21 18:39:18 +00:00
|
|
|
q = (
|
|
|
|
db.session.query(
|
2020-11-01 11:24:19 +00:00
|
|
|
Alias, Contact, EmailLog, sub.c.nb_reply, sub.c.nb_blocked, sub.c.nb_forward
|
2020-08-21 18:39:18 +00:00
|
|
|
)
|
|
|
|
.join(Contact, Alias.id == Contact.alias_id, isouter=True)
|
|
|
|
.join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True)
|
2020-11-01 11:24:19 +00:00
|
|
|
.join(Mailbox, Alias.mailbox_id == Mailbox.id, isouter=True)
|
2020-08-21 18:39:18 +00:00
|
|
|
.filter(Alias.id == sub.c.id)
|
2020-11-01 11:24:19 +00:00
|
|
|
.filter(Alias.id == mailboxes_sub.c.id)
|
2020-08-21 18:39:18 +00:00
|
|
|
.filter(
|
2020-08-21 21:10:23 +00:00
|
|
|
or_(
|
|
|
|
EmailLog.created_at == sub.c.max_created_at,
|
2020-08-26 09:45:24 +00:00
|
|
|
sub.c.max_created_at == None, # no email log yet for this alias
|
2020-11-15 17:42:29 +00:00
|
|
|
Alias.pinned == True,
|
2020-08-21 21:10:23 +00:00
|
|
|
)
|
2020-08-21 18:39:18 +00:00
|
|
|
)
|
2020-08-21 17:51:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if query:
|
|
|
|
q = q.filter(
|
|
|
|
or_(
|
|
|
|
Alias.email.ilike(f"%{query}%"),
|
|
|
|
Alias.note.ilike(f"%{query}%"),
|
|
|
|
Alias.name.ilike(f"%{query}%"),
|
2020-11-01 11:24:19 +00:00
|
|
|
mailboxes_sub.c.nb_matched_mailboxes > 0,
|
2020-08-29 17:03:33 +00:00
|
|
|
Mailbox.email.ilike(f"%{query}%"),
|
2020-08-21 17:51:48 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if alias_filter == "enabled":
|
|
|
|
q = q.filter(Alias.enabled)
|
|
|
|
elif alias_filter == "disabled":
|
|
|
|
q = q.filter(Alias.enabled == False)
|
|
|
|
|
2020-11-15 17:42:29 +00:00
|
|
|
q = q.order_by(Alias.pinned.desc())
|
|
|
|
|
2020-08-21 17:51:48 +00:00
|
|
|
if sort == "old2new":
|
|
|
|
q = q.order_by(Alias.created_at)
|
|
|
|
elif sort == "new2old":
|
|
|
|
q = q.order_by(Alias.created_at.desc())
|
|
|
|
elif sort == "a2z":
|
|
|
|
q = q.order_by(Alias.email)
|
|
|
|
elif sort == "z2a":
|
|
|
|
q = q.order_by(Alias.email.desc())
|
|
|
|
else:
|
|
|
|
# default sorting
|
2020-08-21 21:10:23 +00:00
|
|
|
q = q.order_by(latest_activity.desc())
|
2020-08-21 17:51:48 +00:00
|
|
|
|
|
|
|
q = list(q.limit(PAGE_LIMIT).offset(page_id * PAGE_LIMIT))
|
|
|
|
|
2020-08-21 21:10:23 +00:00
|
|
|
ret = []
|
2020-10-30 12:05:45 +00:00
|
|
|
for alias, contact, email_log, nb_reply, nb_blocked, nb_forward in q:
|
2020-08-21 17:51:48 +00:00
|
|
|
ret.append(
|
|
|
|
AliasInfo(
|
|
|
|
alias=alias,
|
|
|
|
mailbox=alias.mailbox,
|
|
|
|
mailboxes=alias.mailboxes,
|
|
|
|
nb_forward=nb_forward,
|
|
|
|
nb_blocked=nb_blocked,
|
|
|
|
nb_reply=nb_reply,
|
|
|
|
latest_email_log=email_log,
|
|
|
|
latest_contact=contact,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2020-04-05 14:32:38 +00:00
|
|
|
def get_alias_info(alias: Alias) -> AliasInfo:
|
|
|
|
q = (
|
|
|
|
db.session.query(Contact, EmailLog)
|
|
|
|
.filter(Contact.alias_id == alias.id)
|
|
|
|
.filter(EmailLog.contact_id == Contact.id)
|
|
|
|
)
|
|
|
|
|
2020-04-25 09:14:17 +00:00
|
|
|
alias_info = AliasInfo(
|
2020-05-03 13:56:45 +00:00
|
|
|
alias=alias,
|
|
|
|
nb_blocked=0,
|
|
|
|
nb_forward=0,
|
|
|
|
nb_reply=0,
|
|
|
|
mailbox=alias.mailbox,
|
|
|
|
mailboxes=[alias.mailbox],
|
2020-04-25 09:14:17 +00:00
|
|
|
)
|
2020-04-05 14:32:38 +00:00
|
|
|
|
|
|
|
for _, el in q:
|
|
|
|
if el.is_reply:
|
|
|
|
alias_info.nb_reply += 1
|
|
|
|
elif el.blocked:
|
|
|
|
alias_info.nb_blocked += 1
|
|
|
|
else:
|
|
|
|
alias_info.nb_forward += 1
|
|
|
|
|
|
|
|
return alias_info
|
|
|
|
|
|
|
|
|
2020-05-23 17:18:24 +00:00
|
|
|
def get_alias_info_v2(alias: Alias, mailbox=None) -> AliasInfo:
|
|
|
|
if not mailbox:
|
|
|
|
mailbox = alias.mailbox
|
|
|
|
|
2020-04-06 20:26:35 +00:00
|
|
|
q = (
|
|
|
|
db.session.query(Contact, EmailLog)
|
|
|
|
.filter(Contact.alias_id == alias.id)
|
|
|
|
.filter(EmailLog.contact_id == Contact.id)
|
|
|
|
)
|
|
|
|
|
|
|
|
latest_activity: Arrow = alias.created_at
|
|
|
|
latest_email_log = None
|
|
|
|
latest_contact = None
|
|
|
|
|
2020-04-25 09:14:17 +00:00
|
|
|
alias_info = AliasInfo(
|
2020-05-03 13:56:45 +00:00
|
|
|
alias=alias,
|
|
|
|
nb_blocked=0,
|
|
|
|
nb_forward=0,
|
|
|
|
nb_reply=0,
|
|
|
|
mailbox=mailbox,
|
|
|
|
mailboxes=[mailbox],
|
2020-04-25 09:14:17 +00:00
|
|
|
)
|
2020-04-06 20:26:35 +00:00
|
|
|
|
2020-05-03 13:56:45 +00:00
|
|
|
for m in alias._mailboxes:
|
|
|
|
alias_info.mailboxes.append(m)
|
|
|
|
|
|
|
|
# remove duplicates
|
|
|
|
# can happen that alias.mailbox_id also appears in AliasMailbox table
|
|
|
|
alias_info.mailboxes = list(set(alias_info.mailboxes))
|
|
|
|
|
2020-04-06 20:26:35 +00:00
|
|
|
for contact, email_log in q:
|
|
|
|
if email_log.is_reply:
|
|
|
|
alias_info.nb_reply += 1
|
|
|
|
elif email_log.blocked:
|
|
|
|
alias_info.nb_blocked += 1
|
|
|
|
else:
|
|
|
|
alias_info.nb_forward += 1
|
|
|
|
|
|
|
|
if email_log.created_at > latest_activity:
|
|
|
|
latest_activity = email_log.created_at
|
|
|
|
latest_email_log = email_log
|
|
|
|
latest_contact = contact
|
|
|
|
|
|
|
|
alias_info.latest_contact = latest_contact
|
|
|
|
alias_info.latest_email_log = latest_email_log
|
|
|
|
|
|
|
|
return alias_info
|
|
|
|
|
|
|
|
|
2020-04-05 14:32:38 +00:00
|
|
|
def get_alias_contacts(alias, page_id: int) -> [dict]:
|
|
|
|
q = (
|
|
|
|
Contact.query.filter_by(alias_id=alias.id)
|
|
|
|
.order_by(Contact.id.desc())
|
|
|
|
.limit(PAGE_LIMIT)
|
|
|
|
.offset(page_id * PAGE_LIMIT)
|
|
|
|
)
|
|
|
|
|
|
|
|
res = []
|
|
|
|
for fe in q.all():
|
|
|
|
res.append(serialize_contact(fe))
|
|
|
|
|
|
|
|
return res
|