stash
This commit is contained in:
parent
a4d79896da
commit
5ddd8c0b4b
15 changed files with 180 additions and 78 deletions
|
@ -1,28 +0,0 @@
|
|||
# Generated by Django 4.2.7 on 2024-04-26 13:08
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('mail', '0004_alter_emailattachment_file'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserNotificationChannel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('channel_type', models.CharField(choices=[('telegram', 'telegram'), ('email', 'email')], max_length=255)),
|
||||
('channel_target', models.CharField(max_length=255)),
|
||||
('event_filter', models.CharField(max_length=255)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -41,13 +41,4 @@ class EmailAttachment(AbstractFile):
|
|||
name = models.CharField(max_length=255)
|
||||
|
||||
|
||||
class UserNotificationChannel(models.Model):
|
||||
user = models.ForeignKey(ExtendedUser, models.CASCADE)
|
||||
channel_type = models.CharField(choices=[('telegram', 'telegram'), ('email', 'email')], max_length=255)
|
||||
channel_target = models.CharField(max_length=255)
|
||||
event_filter = models.CharField(max_length=255)
|
||||
active = models.BooleanField(default=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def validate_constraints(self, exclude=None): # TODO: email -> emailaddress, telegram -> chatid
|
||||
return True
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
from aiohttp.client import ClientSession
|
||||
from channels.layers import get_channel_layer
|
||||
from channels.db import database_sync_to_async
|
||||
from urllib.parse import quote as urlencode
|
||||
|
||||
from core.settings import TELEGRAM_BOT_TOKEN, TELEGRAM_GROUP_CHAT_ID
|
||||
from mail.models import UserNotificationChannel
|
||||
from mail.protocol import send_smtp, make_notification
|
||||
|
||||
|
||||
async def http_get(url):
|
||||
async with ClientSession() as session:
|
||||
async with session.get(url) as response:
|
||||
return await response.text()
|
||||
|
||||
|
||||
async def telegram_notify(message, chat_id):
|
||||
encoded_message = urlencode(message)
|
||||
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage?chat_id={chat_id}&text={encoded_message}"
|
||||
return await http_get(url)
|
||||
|
||||
|
||||
async def email_notify(message, email):
|
||||
mail = make_notification(message, email)
|
||||
await send_smtp(mail)
|
||||
|
||||
|
||||
class NotificationDispatcher:
|
||||
channel_layer = None
|
||||
room_group_name = "general"
|
||||
|
||||
def __init__(self):
|
||||
self.channel_layer = get_channel_layer('default')
|
||||
if not self.channel_layer:
|
||||
raise Exception("Could not get channel layer")
|
||||
|
||||
@database_sync_to_async
|
||||
def get_notification_targets(self):
|
||||
channels = UserNotificationChannel.objects.filter(active=True)
|
||||
return list(channels)
|
||||
|
||||
async def run_forever(self):
|
||||
# Infinite loop to continuously listen for messages
|
||||
print("Listening for messages...")
|
||||
channel_name = await self.channel_layer.new_channel()
|
||||
await self.channel_layer.group_add(self.room_group_name, channel_name)
|
||||
print("Channel name:", channel_name)
|
||||
while True:
|
||||
# Blocking receive to get the message from the channel layer
|
||||
message = await self.channel_layer.receive(channel_name)
|
||||
|
||||
if (message and 'type' in message and message['type'] == 'generic.event' and 'name' in message and
|
||||
message['name'] == 'user_notification'):
|
||||
if 'message' in message and 'event_id' in message:
|
||||
await self.dispatch(message['message'], message['event_id'])
|
||||
else:
|
||||
print("Error: Invalid message format")
|
||||
|
||||
async def dispatch(self, message, event_id):
|
||||
print("Dispatching message:", message, "with event_id:", event_id)
|
||||
targets = await self.get_notification_targets()
|
||||
await telegram_notify(message, TELEGRAM_GROUP_CHAT_ID)
|
||||
for target in targets:
|
||||
if target.channel_type == 'telegram':
|
||||
print("Sending telegram notification to:", target.channel_target)
|
||||
await telegram_notify(message, target.channel_target)
|
||||
elif target.channel_type == 'email':
|
||||
print("Sending email notification to:", target.channel_target)
|
||||
await email_notify(message, target.channel_target)
|
||||
else:
|
||||
print("Unknown channel type:", target.channel_type)
|
|
@ -5,8 +5,8 @@ from channels.layers import get_channel_layer
|
|||
from channels.db import database_sync_to_async
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from core.settings import PRIMARY_HOST
|
||||
from mail.models import Email, EventAddress, EmailAttachment
|
||||
from notifications.templates import render_auto_reply
|
||||
from notify_sessions.models import SystemEvent
|
||||
from tickets.models import IssueThread
|
||||
|
||||
|
@ -83,14 +83,13 @@ def make_reply(reply_email, references=None, event=None):
|
|||
return reply
|
||||
|
||||
|
||||
def make_notification(message, to, event=None): # TODO where should replies to this go
|
||||
def make_notification(message, to, title): # TODO where should replies to this go
|
||||
from email.message import EmailMessage
|
||||
from core.settings import MAIL_DOMAIN
|
||||
event = event or "mail"
|
||||
notification = EmailMessage()
|
||||
notification["From"] = "notifications@%s" % MAIL_DOMAIN
|
||||
notification["To"] = to
|
||||
notification["Subject"] = f"System3 Notification"
|
||||
notification["Subject"] = f"[C3LF Notification]%s" % title
|
||||
# notification["Reply-To"] = f"{event}@{MAIL_DOMAIN}"
|
||||
# notification["In-Reply-To"] = email.reference
|
||||
# notification["Message-ID"] = email.id + "@" + MAIL_DOMAIN
|
||||
|
@ -198,11 +197,11 @@ def receive_email(envelope, log=None):
|
|||
header_in_reply_to = parsed.get('In-Reply-To')
|
||||
header_message_id = parsed.get('Message-ID')
|
||||
|
||||
#if header_from != envelope.mail_from:
|
||||
# if header_from != envelope.mail_from:
|
||||
# log.warning("Header from does not match envelope from")
|
||||
# log.info(f"Header from: {header_from}, envelope from: {envelope.mail_from}")
|
||||
#
|
||||
#if header_to != envelope.rcpt_tos[0]:
|
||||
#
|
||||
# if header_to != envelope.rcpt_tos[0]:
|
||||
# log.warning("Header to does not match envelope to")
|
||||
# log.info(f"Header to: {header_to}, envelope to: {envelope.rcpt_tos[0]}")
|
||||
|
||||
|
@ -231,16 +230,7 @@ def receive_email(envelope, log=None):
|
|||
references = collect_references(active_issue_thread)
|
||||
if not sender.startswith('noreply'):
|
||||
subject = f"Re: {subject} [#{active_issue_thread.short_uuid()}]"
|
||||
body = '''Your request (#{}) has been received and will be reviewed by our lost&found angels.
|
||||
|
||||
We are reviewing incoming requests during the event and teardown. Immediately after the event, expect a delay as the \
|
||||
workload is high. We will not forget about your request and get back in touch once we have updated information on your \
|
||||
request. Requests for devices, wallets, credit cards or similar items will be handled with priority.
|
||||
|
||||
If you happen to find your lost item or just want to add additional information, please reply to this email. Please \
|
||||
do not create a new request.
|
||||
|
||||
Your c3lf (Cloakroom + Lost&Found) Team'''.format(active_issue_thread.short_uuid())
|
||||
body = render_auto_reply(active_issue_thread)
|
||||
reply_email = Email.objects.create(
|
||||
sender=recipient, recipient=sender, body=body, subject=subject,
|
||||
in_reply_to=header_message_id, event=target_event, issue_thread=active_issue_thread)
|
||||
|
@ -251,20 +241,7 @@ Your c3lf (Cloakroom + Lost&Found) Team'''.format(active_issue_thread.short_uuid
|
|||
active_issue_thread.state = 'pending_open'
|
||||
active_issue_thread.save()
|
||||
|
||||
notification = None
|
||||
if len(active_issue_thread.name) > 50:
|
||||
notify_subject = active_issue_thread.name[:47] + "..."
|
||||
else:
|
||||
notify_subject = active_issue_thread.name
|
||||
eventslug = target_event.slug if target_event else "37C3" # TODO 37C3 should not be hardcoded
|
||||
if new:
|
||||
notification = f"""New issue \"{active_issue_thread.name}\" [{active_issue_thread.short_uuid()}] created
|
||||
https://{PRIMARY_HOST}/{eventslug}/ticket/{active_issue_thread.id}/"""
|
||||
else:
|
||||
notification = f"""Reply to issue \"{active_issue_thread.name}\" [{active_issue_thread.short_uuid()}]
|
||||
https://{PRIMARY_HOST}/{eventslug}/ticket/{active_issue_thread.id}/"""
|
||||
|
||||
return email, new, reply, notification
|
||||
return email, new, reply, active_issue_thread
|
||||
|
||||
|
||||
class LMTPHandler:
|
||||
|
@ -286,7 +263,7 @@ class LMTPHandler:
|
|||
content = None
|
||||
try:
|
||||
content = envelope.content
|
||||
email, new, reply, notification = await database_sync_to_async(receive_email)(envelope, log)
|
||||
email, new, reply, thread = await database_sync_to_async(receive_email)(envelope, log)
|
||||
log.info(f"Created email {email.id}")
|
||||
systemevent = await database_sync_to_async(SystemEvent.objects.create)(type='email received',
|
||||
reference=email.id)
|
||||
|
@ -296,11 +273,10 @@ class LMTPHandler:
|
|||
'general', {"type": "generic.event", "name": "send_message_to_frontend", "event_id": systemevent.id,
|
||||
"message": "email received"})
|
||||
log.info(f"Sent message to frontend")
|
||||
if notification:
|
||||
log.info(f"Sending notification {notification}")
|
||||
if thread:
|
||||
await channel_layer.group_send(
|
||||
'general', {"type": "generic.event", "name": "user_notification", "event_id": systemevent.id,
|
||||
"message": notification})
|
||||
"ticket": thread, "new": new})
|
||||
if new and reply:
|
||||
log.info('Sending message to %s' % reply['To'])
|
||||
await send_smtp(reply)
|
||||
|
|
|
@ -2,7 +2,7 @@ from django.contrib.auth.models import Permission
|
|||
from django.test import TestCase
|
||||
|
||||
from authentication.models import ExtendedUser
|
||||
from mail.models import UserNotificationChannel
|
||||
from notifications.models import UserNotificationChannel
|
||||
|
||||
|
||||
class UserNotificationTestCase(TestCase):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue