stash
This commit is contained in:
parent
b8c3bcfa3b
commit
b00976e0fa
6 changed files with 72 additions and 4 deletions
26
TODO.md
26
TODO.md
|
@ -71,8 +71,30 @@
|
||||||
* [ ] concept: purge old tickets
|
* [ ] concept: purge old tickets
|
||||||
* [ ] concept: purge old items
|
* [ ] concept: purge old items
|
||||||
* [ ] concept: auto email stale after x days
|
* [ ] concept: auto email stale after x days
|
||||||
|
* [ ] frontend: reply email field multiline
|
||||||
|
* [ ] concept: customisable autoreply (message, title) + ticket id
|
||||||
|
* [ ] frontend: show from address in issueThread or internal user
|
||||||
|
* [ ] manual ticket creation
|
||||||
|
* [ ] hide citation for incoming mails
|
||||||
|
* [ ] frontend: different icons for send and received mails
|
||||||
|
* [ ] frontend: change ticket status
|
||||||
|
* new mail -> new,
|
||||||
|
* op reply ->
|
||||||
|
* waiting for detail
|
||||||
|
* waiting for address / shipment information
|
||||||
|
* customer reply -> open
|
||||||
|
* needs physical confirmation
|
||||||
|
* needs to be shipped
|
||||||
|
* dhl mail -> closed: shipped
|
||||||
|
* closed: not found
|
||||||
|
* closed: not our problem
|
||||||
|
* closed: timeout (no reply)
|
||||||
|
* closed: duplicate
|
||||||
|
* closed: spam
|
||||||
|
* [ ] concept: split ticket for multiple items
|
||||||
|
* [ ] mail signature
|
||||||
|
* [ ] guru api integration
|
||||||
|
|
||||||
## Priority: TODO
|
## Priority: TODO
|
||||||
|
|
||||||
* send mails from web frontend
|
* manual ticket creation
|
||||||
* login / user management
|
|
||||||
|
|
|
@ -7,10 +7,12 @@ from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
|
from channels.layers import get_channel_layer
|
||||||
|
|
||||||
from core.settings import MAIL_DOMAIN
|
from core.settings import MAIL_DOMAIN
|
||||||
from mail.models import Email
|
from mail.models import Email
|
||||||
from mail.protocol import send_smtp, make_reply, collect_references
|
from mail.protocol import send_smtp, make_reply, collect_references
|
||||||
|
from notify_sessions.models import SystemEvent
|
||||||
from tickets.models import IssueThread
|
from tickets.models import IssueThread
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,9 +82,34 @@ def reply(request, pk):
|
||||||
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
@permission_required('tickets.add_issuethread_manual', raise_exception=True)
|
||||||
|
def manual_ticket(request):
|
||||||
|
issue = IssueThread.objects.create(
|
||||||
|
name=request.data['name'],
|
||||||
|
manually_created=True,
|
||||||
|
)
|
||||||
|
email = Email.objects.create(
|
||||||
|
issue_thread=issue,
|
||||||
|
sender=request.data['sender'],
|
||||||
|
recipient=request.data['recipient'],
|
||||||
|
subject=request.data['name'],
|
||||||
|
body=request.data['body'],
|
||||||
|
)
|
||||||
|
systemevent = SystemEvent.objects.create(type='email received', reference=email.id)
|
||||||
|
channel_layer = get_channel_layer()
|
||||||
|
async_to_sync(channel_layer.group_send)(
|
||||||
|
'general', {"type": "generic.event", "name": "send_message_to_frontend", "event_id": systemevent.id,
|
||||||
|
"message": "email received"}
|
||||||
|
)
|
||||||
|
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
router.register(r'tickets', IssueViewSet, basename='issues')
|
router.register(r'tickets', IssueViewSet, basename='issues')
|
||||||
|
|
||||||
urlpatterns = router.urls + [
|
urlpatterns = router.urls + [
|
||||||
path('tickets/<int:pk>/reply/', reply, name='reply'),
|
path('tickets/<int:pk>/reply/', reply, name='reply'),
|
||||||
|
path('tickets/manual', manual_ticket, name='manual_ticket'),
|
||||||
]
|
]
|
||||||
|
|
18
core/tickets/migrations/0002_issuethread_manually_created.py
Normal file
18
core/tickets/migrations/0002_issuethread_manually_created.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2.7 on 2023-12-17 23:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tickets', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='issuethread',
|
||||||
|
name='manually_created',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -10,6 +10,7 @@ class IssueThread(SoftDeleteModel):
|
||||||
state = models.CharField(max_length=255, default='new')
|
state = models.CharField(max_length=255, default='new')
|
||||||
assigned_to = models.CharField(max_length=255, null=True)
|
assigned_to = models.CharField(max_length=255, null=True)
|
||||||
last_activity = models.DateTimeField(auto_now=True)
|
last_activity = models.DateTimeField(auto_now=True)
|
||||||
|
manually_created = models.BooleanField(default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = [
|
permissions = [
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<table class="table table-striped table-dark">
|
<table class="table table-striped table-dark" style="table-layout: fixed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<table class="table table-striped table-dark">
|
<table class="table table-striped table-dark" style="table-layout: fixed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
|
|
Loading…
Reference in a new issue