diff --git a/core/authentication/migrations/0002_groups.py b/core/authentication/migrations/0002_groups.py new file mode 100644 index 0000000..f7d9f34 --- /dev/null +++ b/core/authentication/migrations/0002_groups.py @@ -0,0 +1,35 @@ +# Generated by Django 4.2.7 on 2023-11-26 00:16 + +from django.conf import settings +from django.db import migrations +from django.contrib.auth.models import Permission, Group + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('authentication', '0001_initial'), + ('inventory', '0003_alter_item_options'), + ('tickets', '0003_alter_issuethread_options'), + ] + + def create_groups(apps, schema_editor): + admins = Group.objects.create(name='Admin') + orga = Group.objects.create(name='Orga') + team = Group.objects.create(name='Team') + users = Group.objects.create(name='User') + admins.permissions.add(*Permission.objects.all()) + users.permissions.add(*Permission.objects.filter(codename__in= + ['view_item', 'add_item', 'change_item', 'match_item'])) + team.permissions.add(*Permission.objects.filter(codename__in= + ['delete_item', 'view_issuethread', 'add_issuethread', + 'change_issuethread', 'delete_issuethread', 'send_mail']), + *users.permissions.all()) + orga.permissions.add(*Permission.objects.filter(codename__in=['add_event']), + *team.permissions.all()) + + operations = [ + migrations.RunPython(create_groups), + ] diff --git a/core/inventory/migrations/0003_alter_item_options.py b/core/inventory/migrations/0003_alter_item_options.py new file mode 100644 index 0000000..0efebee --- /dev/null +++ b/core/inventory/migrations/0003_alter_item_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2023-12-06 13:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0002_container_deleted_at_container_is_deleted_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='item', + options={'permissions': [('match_item', 'Can match item')]}, + ), + ] diff --git a/core/inventory/models.py b/core/inventory/models.py index 6f5bb1e..c3a3961 100644 --- a/core/inventory/models.py +++ b/core/inventory/models.py @@ -29,7 +29,9 @@ class Item(SoftDeleteModel): class Meta: unique_together = (('uid', 'event'),) - + permissions = [ + ('match_item', 'Can match item') + ] class Container(SoftDeleteModel): cid = models.AutoField(primary_key=True) diff --git a/core/mail/protocol.py b/core/mail/protocol.py index e4da5d5..dae4d96 100644 --- a/core/mail/protocol.py +++ b/core/mail/protocol.py @@ -17,14 +17,15 @@ def collect_references(issue_thread): return references -def make_reply(reply_email, references=None): +def make_reply(reply_email, references=None, event=None, issue_thread=None): from email.message import EmailMessage from core.settings import MAIL_DOMAIN - + event = event or "noreply" reply = EmailMessage() reply["From"] = reply_email.sender reply["To"] = reply_email.recipient reply["Subject"] = reply_email.subject + reply["Reply-To"] = f"{event}+{issue_thread}@{MAIL_DOMAIN}" if reply_email.in_reply_to: reply["In-Reply-To"] = reply_email.in_reply_to if reply_email.reference: diff --git a/core/mail/tests/v2/test_mails.py b/core/mail/tests/v2/test_mails.py index 3c7a292..f58918c 100644 --- a/core/mail/tests/v2/test_mails.py +++ b/core/mail/tests/v2/test_mails.py @@ -116,7 +116,6 @@ class LMTPHandlerTestCase(TestCase): # TODO replace with less hacky test envelope = Envelope() envelope.mail_from = 'test1@test' envelope.rcpt_tos = ['test2@test'] - # envelope.content = b'Subject: Re: test\nFrom: test3@test\nTo: test4@test\nMessage-ID: 3@test\nIn-Reply-To: 2@localhost\n\ntest' envelope.content = (f'Subject: Re: test\nFrom: test3@test\nTo: test4@test\nMessage-ID: <3@test>\n' f'In-Reply-To: {mail1_reply.reference}'.encode('utf-8') + b'\n\ntest') result = async_to_sync(handler.handle_DATA)(server, session, envelope) @@ -134,65 +133,3 @@ class LMTPHandlerTestCase(TestCase): # TODO replace with less hacky test self.assertEqual(IssueThread.objects.all()[0].name, 'test') self.assertEqual(IssueThread.objects.all()[0].state, 'new') self.assertEqual(IssueThread.objects.all()[0].assigned_to, None) - -# class AsyncLMTPTestCase(TestCase): -# -# def setUp(self): -# server = mock.Mock() -# self.create_unix_server = make_mocked_coro(server) -# self.wait_closed = make_mocked_coro() -# self.loop = asyncio.new_event_loop() -# self.loop.create_unix_server = self.create_unix_server -# asyncio.set_event_loop(self.loop) -# -# async def test_connect(self): -# server = await UnixSocketLMTPController(LMTPHandler(), unix_socket='lmtp.sock', loop=self.loop).serve() -# self.assertEqual(self.create_unix_server.call_count, 1) -# self.assertEqual(self.wait_closed.call_count, 0) -# server.close() -# # self.assertEqual(self.wait_closed.call_count, 1) -# -# def test_receive_mail(self): -# from logging import getLogger -# from aiosmtpd.lmtp import LMTP -# from asgiref.sync import async_to_sync -# log = getLogger('mail.log') -# log.addHandler(logging.StreamHandler()) -# log.setLevel(logging.DEBUG) -# handler = LMTP(LMTPHandler(), loop=self.loop) -# transport = mock.Mock() -# handler.connection_made(transport) -# -# def _handle_client(): -# print("Handling client") -# async_to_sync(handler._handle_client)() -# print("Client handled") -# -# thread = threading.Thread(target=_handle_client) -# thread.start() -# -# # handler.data_received( -# # b'HELO test\nMAIL FROM:\nRCPT TO:\nDATA\nSubject: test\nFrom: test1@test\nTo: ' -# # b'test2@test\n\ntest\n.\nQUIT') -# handler.data_received(b'HELO test\n') -# handler.data_received(b'MAIL FROM:\n') -# handler.data_received(b'RCPT TO:\n') -# handler.data_received(b'DATA\n') -# handler.data_received(b'Subject: test\n') -# handler.data_received(b'From: test1@test\n') -# handler.data_received(b'To: test2@test\n') -# handler.data_received(b'\n') -# handler.data_received(b'test\n') -# handler.data_received(b'.\n') -# handler.data_received(b'QUIT\n') -# -# thread.join() -# -# handler.connection_lost(None) -# thread.join() -# -# # self.assertEqual(len(Email.objects.all()), 1) -# # self.assertEqual(Email.objects.all()[0].subject, 'test') -# # self.assertEqual(Email.objects.all()[0].body, 'test') -# # self.assertEqual(Email.objects.all()[0].sender, 'test') -# # self.assertEqual(Email.objects.all()[0].recipient, 'test@test') diff --git a/core/tickets/migrations/0003_alter_issuethread_options.py b/core/tickets/migrations/0003_alter_issuethread_options.py new file mode 100644 index 0000000..4d53778 --- /dev/null +++ b/core/tickets/migrations/0003_alter_issuethread_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2023-12-06 13:47 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0002_issuethread_assigned_to_issuethread_last_activity_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='issuethread', + options={'permissions': [('send_mail', 'Can send mail')]}, + ), + ] diff --git a/core/tickets/models.py b/core/tickets/models.py index 5751288..44da336 100644 --- a/core/tickets/models.py +++ b/core/tickets/models.py @@ -11,6 +11,11 @@ class IssueThread(SoftDeleteModel): assigned_to = models.CharField(max_length=255, null=True) last_activity = models.DateTimeField(auto_now=True) + class Meta: + permissions = [ + ('send_mail', 'Can send mail'), + ] + class Comment(models.Model): id = models.AutoField(primary_key=True)