Allow (un)subscribing by mailing ~u/t[/1]/[un]subscribe
This commit is contained in:
parent
4270950afe
commit
b7b5abb83a
122
todosrht-lmtp
122
todosrht-lmtp
|
@ -10,7 +10,7 @@ from email.utils import parseaddr
|
|||
from grp import getgrnam
|
||||
from todosrht.access import get_tracker, get_ticket
|
||||
from todosrht.types import TicketAccess, TicketResolution, Tracker, Ticket, User
|
||||
from todosrht.types import Label, TicketLabel, Event, EventType, ParticipantType
|
||||
from todosrht.types import Label, TicketLabel, TicketSubscription, Event, EventType, ParticipantType
|
||||
from todosrht.tickets import add_comment, get_participant_for_email, submit_ticket
|
||||
from todosrht.webhooks import UserWebhook, TrackerWebhook, TicketWebhook
|
||||
from srht.validation import Validation
|
||||
|
@ -28,16 +28,28 @@ class MailHandler:
|
|||
def lookup_destination(self, address, sender):
|
||||
# Address formats are:
|
||||
# Tracker (opening a new ticket):
|
||||
# ~username/tracker@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker@todo.sr.ht
|
||||
# ~username/tracker@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker@todo.sr.ht
|
||||
# Ticket (participating in dicsussion):
|
||||
# ~username/tracker/1234@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker.1234@todo.sr.ht
|
||||
# ~username/tracker/1234@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker.1234@todo.sr.ht
|
||||
# Tracker (un)subscribe:
|
||||
# ~username/tracker/subscribe@todo.sr.ht
|
||||
# ~username/tracker/unsubscribe@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker.subscribe@todo.sr.ht
|
||||
# u.username.tracker.unsubscribe@todo.sr.ht
|
||||
# Ticket (un)subscribe:
|
||||
# ~username/tracker/1234/subscribe@todo.sr.ht
|
||||
# ~username/tracker/1234/unsubscribe@todo.sr.ht
|
||||
# or (for shitty MTAs):
|
||||
# u.username.tracker.1234.subscribe@todo.sr.ht
|
||||
# u.username.tracker.1234.unsubscribe@todo.sr.ht
|
||||
address = address[:address.rfind("@")]
|
||||
# TODO: Subscribe to trackers & tickets via email
|
||||
ticket_id = None
|
||||
sub_action = None
|
||||
if address.startswith("~"):
|
||||
# TODO: user groups
|
||||
parts = address.split("/")
|
||||
|
@ -48,9 +60,28 @@ class MailHandler:
|
|||
try:
|
||||
ticket_id = int(ticket_id)
|
||||
except:
|
||||
return None, None
|
||||
sub_action = ticket_id
|
||||
ticket_id = None
|
||||
if sub_action == "subscribe":
|
||||
sub_action = True
|
||||
elif sub_action == "unsubscribe":
|
||||
sub_action = False
|
||||
else:
|
||||
return None, None, None
|
||||
elif len(parts) == 4:
|
||||
owner, tracker_name, ticket_id, sub_action = parts
|
||||
try:
|
||||
ticket_id = int(ticket_id)
|
||||
except:
|
||||
return None, None, None
|
||||
if sub_action == "subscribe":
|
||||
sub_action = True
|
||||
elif sub_action == "unsubscribe":
|
||||
sub_action = False
|
||||
else:
|
||||
return None, None, None
|
||||
else:
|
||||
return None, None
|
||||
return None, None, None
|
||||
else:
|
||||
address = address.split(".")
|
||||
if len(address) == 3:
|
||||
|
@ -60,20 +91,39 @@ class MailHandler:
|
|||
try:
|
||||
ticket_id = int(ticket_id)
|
||||
except:
|
||||
return None, None
|
||||
sub_action = ticket_id
|
||||
ticket_id = None
|
||||
if sub_action == "subscribe":
|
||||
sub_action = True
|
||||
elif sub_action == "unsubscribe":
|
||||
sub_action = False
|
||||
else:
|
||||
return None, None, None
|
||||
elif len(address) == 5:
|
||||
prefix, owner, tracker_name, ticket_id, sub_action = address
|
||||
try:
|
||||
ticket_id = int(ticket_id)
|
||||
except:
|
||||
return None, None, None
|
||||
if sub_action == "subscribe":
|
||||
sub_action = True
|
||||
elif sub_action == "unsubscribe":
|
||||
sub_action = False
|
||||
else:
|
||||
return None, None, None
|
||||
else:
|
||||
return None, None
|
||||
return None, None, None
|
||||
if prefix == "u":
|
||||
owner = "~" + owner
|
||||
else:
|
||||
# TODO: user groups
|
||||
return None, None
|
||||
return None, None, None
|
||||
# TODO: ACLs for email participants
|
||||
tracker, access = get_tracker(owner, tracker_name, user=sender.user)
|
||||
if not ticket_id:
|
||||
return tracker, access
|
||||
return tracker, sub_action, access
|
||||
ticket, access = get_ticket(tracker, ticket_id, user=sender.user)
|
||||
return ticket, access
|
||||
return ticket, sub_action, access
|
||||
|
||||
async def handle_RCPT(self, server, session,
|
||||
envelope, address, rcpt_options):
|
||||
|
@ -212,11 +262,14 @@ class MailHandler:
|
|||
name, sender_addr = parseaddr(mail["From"])
|
||||
sender = get_participant_for_email(sender_addr, name)
|
||||
|
||||
dest, access = self.lookup_destination(address, sender)
|
||||
dest, sub_action, access = self.lookup_destination(address, sender)
|
||||
if dest is None:
|
||||
print("Rejected, destination not found")
|
||||
return "550 The tracker or ticket you requested does not exist."
|
||||
|
||||
if sub_action is not None:
|
||||
return await self.handle_un_subscription(dest, sender, sub_action)
|
||||
|
||||
body = None
|
||||
for part in mail.walk():
|
||||
if part.is_multipart():
|
||||
|
@ -242,6 +295,43 @@ class MailHandler:
|
|||
else:
|
||||
assert False
|
||||
|
||||
async def handle_un_subscription(self, dest, participant, do_subscribe):
|
||||
if isinstance(dest, Tracker):
|
||||
tracker_id = dest.id
|
||||
ticket_id = None
|
||||
elif isinstance(dest, Ticket):
|
||||
tracker_id = None
|
||||
ticket_id = dest.id
|
||||
else:
|
||||
assert False
|
||||
|
||||
sub = (TicketSubscription.query
|
||||
.filter(TicketSubscription.tracker_id == tracker_id)
|
||||
.filter(TicketSubscription.ticket_id == ticket_id)
|
||||
.filter(TicketSubscription.participant_id == participant.id)
|
||||
).one_or_none()
|
||||
|
||||
if sub:
|
||||
if do_subscribe:
|
||||
return "250 Already subscribed"
|
||||
db.session.delete(sub)
|
||||
else:
|
||||
if not do_subscribe:
|
||||
return "250 Not subscribed"
|
||||
sub = TicketSubscription()
|
||||
sub.tracker_id = tracker_id
|
||||
sub.ticket_id = ticket_id
|
||||
sub.participant_id = participant.id
|
||||
db.session.add(sub)
|
||||
|
||||
db.session.commit()
|
||||
if do_subscribe:
|
||||
print(f"Subscribed to {dest.ref()}")
|
||||
return "250 Subscribed"
|
||||
else:
|
||||
print(f"Unsubscribed from {dest.ref()}")
|
||||
return "250 Unsubscribed"
|
||||
|
||||
async def create_server():
|
||||
sock_gid = getgrnam(cfg("todo.sr.ht::mail", "sock-group")).gr_gid
|
||||
handler = MailHandler()
|
||||
|
|
Loading…
Reference in New Issue