This commit is contained in:
j3d1 2024-04-26 15:18:41 +02:00
parent 79fec60229
commit 82b9f747e2
8 changed files with 103 additions and 2 deletions

View file

@ -40,6 +40,10 @@ LEGACY_USER_PASSWORD = os.getenv('LEGACY_API_PASSWORD', 'legacy_password')
SYSTEM3_VERSION = "0.0.0-dev.0" SYSTEM3_VERSION = "0.0.0-dev.0"
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', '1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi')
TELEGRAM_GROUP_CHAT_ID = os.getenv('TELEGRAM_GROUP_CHAT_ID', '-1234567890')
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [

View file

@ -0,0 +1,28 @@
# 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)),
],
),
]

View file

@ -3,6 +3,7 @@ import random
from django.db import models from django.db import models
from django_softdelete.models import SoftDeleteModel from django_softdelete.models import SoftDeleteModel
from authentication.models import ExtendedUser
from core.settings import MAIL_DOMAIN from core.settings import MAIL_DOMAIN
from files.models import AbstractFile from files.models import AbstractFile
from inventory.models import Event from inventory.models import Event
@ -38,3 +39,15 @@ class EventAddress(models.Model):
class EmailAttachment(AbstractFile): class EmailAttachment(AbstractFile):
email = models.ForeignKey(Email, models.CASCADE, related_name='attachments', null=True) email = models.ForeignKey(Email, models.CASCADE, related_name='attachments', null=True)
name = models.CharField(max_length=255) 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

View file

@ -1,5 +1,22 @@
from aiohttp.client import ClientSession
from channels.layers import get_channel_layer from channels.layers import get_channel_layer
from channels.db import database_sync_to_async 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
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)
class NotificationDispatcher: class NotificationDispatcher:
@ -13,7 +30,8 @@ class NotificationDispatcher:
@database_sync_to_async @database_sync_to_async
def get_notification_targets(self): def get_notification_targets(self):
return [] channels = UserNotificationChannel.objects.filter(active=True)
return list(channels)
async def run_forever(self): async def run_forever(self):
# Infinite loop to continuously listen for messages # Infinite loop to continuously listen for messages
@ -35,5 +53,11 @@ class NotificationDispatcher:
async def dispatch(self, message, event_id): async def dispatch(self, message, event_id):
print("Dispatching message:", message, "with event_id:", event_id) print("Dispatching message:", message, "with event_id:", event_id)
targets = await self.get_notification_targets() targets = await self.get_notification_targets()
await telegram_notify(message, TELEGRAM_GROUP_CHAT_ID)
for target in targets: for target in targets:
print("Sending message to target:", target) if target.channel_type == 'telegram':
await telegram_notify(message, target.channel_target)
if target.channel_type == 'mail':
print("Sending mail to:", target.channel_target)
else:
print("Unknown channel type:", target.channel_type)

View file

@ -0,0 +1,20 @@
from django.contrib.auth.models import Permission
from django.test import TestCase
from authentication.models import ExtendedUser
from mail.models import UserNotificationChannel
class UserNotificationTestCase(TestCase):
def setUp(self):
super().setUp()
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
self.user.user_permissions.add(*Permission.objects.all())
self.user.save()
self.channel = UserNotificationChannel.objects.create(user=self.user, channel_type='telegram',
channel_target='123456789',
event_filter='*', active=True)
async def test_telegram_notify(self):
pass

View file

@ -1,3 +1,6 @@
aiodns==3.2.0
aiohttp==3.9.5
aiosignal==1.3.1
aiosmtpd==1.4.4.post2 aiosmtpd==1.4.4.post2
aiosmtplib==3.0.1 aiosmtplib==3.0.1
anyio==4.1.0 anyio==4.1.0
@ -28,6 +31,7 @@ django-rest-knox==4.2.0
django-soft-delete==0.9.21 django-soft-delete==0.9.21
djangorestframework==3.14.0 djangorestframework==3.14.0
drf-yasg==1.21.7 drf-yasg==1.21.7
frozenlist==1.4.1
h11==0.14.0 h11==0.14.0
hyperlink==21.0.0 hyperlink==21.0.0
idna==3.4 idna==3.4
@ -38,11 +42,13 @@ Jinja2==3.1.2
MarkupSafe==2.1.3 MarkupSafe==2.1.3
msgpack==1.0.7 msgpack==1.0.7
msgpack-python==0.5.6 msgpack-python==0.5.6
multidict==6.0.5
openapi-codec==1.3.2 openapi-codec==1.3.2
packaging==23.2 packaging==23.2
Pillow==10.1.0 Pillow==10.1.0
pyasn1==0.5.1 pyasn1==0.5.1
pyasn1-modules==0.3.0 pyasn1-modules==0.3.0
pycares==4.4.0
pycparser==2.21 pycparser==2.21
pyOpenSSL==23.3.0 pyOpenSSL==23.3.0
python-dotenv==1.0.0 python-dotenv==1.0.0
@ -65,4 +71,5 @@ urllib3==2.1.0
uvicorn==0.24.0.post1 uvicorn==0.24.0.post1
watchfiles==0.21.0 watchfiles==0.21.0
websockets==12.0 websockets==12.0
yarl==1.9.4
zope.interface==6.1 zope.interface==6.1

View file

@ -1,3 +1,6 @@
aiodns==3.2.0
aiohttp==3.9.5
aiosignal==1.3.1
aiosmtpd==1.4.4.post2 aiosmtpd==1.4.4.post2
aiosmtplib==3.0.1 aiosmtplib==3.0.1
asgiref==3.7.2 asgiref==3.7.2

View file

@ -9,3 +9,5 @@ LEGACY_API_USER={{ legacy_api_user }}
LEGACY_API_PASSWORD={{ legacy_api_password }} LEGACY_API_PASSWORD={{ legacy_api_password }}
MEDIA_ROOT=/var/www/c3lf-sys3/userfiles MEDIA_ROOT=/var/www/c3lf-sys3/userfiles
STATIC_ROOT=/var/www/c3lf-sys3/staticfiles STATIC_ROOT=/var/www/c3lf-sys3/staticfiles
TELEGRAM_GROUP_CHAT_ID={{ telegram_group_chat_id }}
TELEGRAM_BOT_TOKEN={{ telegram_bot_token }}