From bd413837c256a4187c160d7f88daaf9ddf736bd2 Mon Sep 17 00:00:00 2001 From: Benbb96 Date: Fri, 24 Jun 2022 22:22:08 +0200 Subject: [PATCH 01/12] Create FollowUp serializer with its Viewset and add it in urls --- helpdesk/serializers.py | 14 ++++++++++++-- helpdesk/urls.py | 3 ++- helpdesk/views/api.py | 13 +++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/helpdesk/serializers.py b/helpdesk/serializers.py index b5734c49..66264abf 100644 --- a/helpdesk/serializers.py +++ b/helpdesk/serializers.py @@ -4,7 +4,7 @@ from django.contrib.humanize.templatetags import humanize from rest_framework.exceptions import ValidationError from .forms import TicketForm -from .models import Ticket, CustomField +from .models import Ticket, CustomField, FollowUp from .lib import format_time_spent from .user import HelpdeskUser @@ -71,12 +71,22 @@ class DatatablesTicketSerializer(serializers.ModelSerializer): return obj.kbitem.title if obj.kbitem else "" +class FollowUpSerializer(serializers.ModelSerializer): + class Meta: + model = FollowUp + fields = ( + 'id', 'ticket', 'date', 'title', 'comment', 'public', 'user', 'new_status', 'message_id', 'time_spent' + ) + + class TicketSerializer(serializers.ModelSerializer): + followup_set = FollowUpSerializer(many=True, read_only=True) + class Meta: model = Ticket fields = ( 'id', 'queue', 'title', 'description', 'resolution', 'submitter_email', 'assigned_to', 'status', 'on_hold', - 'priority', 'due_date', 'merged_to' + 'priority', 'due_date', 'merged_to', 'followup_set' ) def __init__(self, *args, **kwargs): diff --git a/helpdesk/urls.py b/helpdesk/urls.py index 03924e98..4079fb28 100644 --- a/helpdesk/urls.py +++ b/helpdesk/urls.py @@ -17,7 +17,7 @@ from rest_framework.routers import DefaultRouter from helpdesk.decorators import helpdesk_staff_member_required, protect_view from helpdesk.views import feeds, staff, public, login from helpdesk import settings as helpdesk_settings -from helpdesk.views.api import TicketViewSet, CreateUserView +from helpdesk.views.api import TicketViewSet, CreateUserView, FollowUpViewSet if helpdesk_settings.HELPDESK_KB_ENABLED: from helpdesk.views import kb @@ -176,6 +176,7 @@ urlpatterns += [ if helpdesk_settings.HELPDESK_ACTIVATE_API_ENDPOINT: router = DefaultRouter() router.register(r"tickets", TicketViewSet, basename="ticket") + router.register(r"followups", FollowUpViewSet, basename="followups") router.register(r"users", CreateUserView, basename="user") urlpatterns += [re_path(r"^api/", include(router.urls))] diff --git a/helpdesk/views/api.py b/helpdesk/views/api.py index 266f821f..a77514a2 100644 --- a/helpdesk/views/api.py +++ b/helpdesk/views/api.py @@ -4,8 +4,8 @@ from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import CreateModelMixin from django.contrib.auth import get_user_model -from helpdesk.models import Ticket -from helpdesk.serializers import TicketSerializer, UserSerializer +from helpdesk.models import Ticket, FollowUp +from helpdesk.serializers import TicketSerializer, UserSerializer, FollowUpSerializer class TicketViewSet(viewsets.ModelViewSet): @@ -28,6 +28,15 @@ class TicketViewSet(viewsets.ModelViewSet): return ticket +class FollowUpViewSet(viewsets.ModelViewSet): + """ + A viewset that provides the standard actions to handle FollowUp + """ + queryset = FollowUp.objects.all() + serializer_class = FollowUpSerializer + permission_classes = [IsAdminUser] + + class CreateUserView(CreateModelMixin, GenericViewSet): queryset = get_user_model().objects.all() serializer_class = UserSerializer From 9dbe283dd442b89c781508774f75a5bcc7004ae5 Mon Sep 17 00:00:00 2001 From: Benbb96 Date: Fri, 24 Jun 2022 23:45:26 +0200 Subject: [PATCH 02/12] Create FollowUpAttachment serializer + handle attachment in TicketSerializer and in FollowUpSerializer in order to attach directly one or multiple attachments to the created followup. --- helpdesk/serializers.py | 34 +++++++++++++++++++++++++++++----- helpdesk/urls.py | 3 ++- helpdesk/views/api.py | 13 ++++++++----- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/helpdesk/serializers.py b/helpdesk/serializers.py index 66264abf..ebd5cb30 100644 --- a/helpdesk/serializers.py +++ b/helpdesk/serializers.py @@ -4,8 +4,8 @@ from django.contrib.humanize.templatetags import humanize from rest_framework.exceptions import ValidationError from .forms import TicketForm -from .models import Ticket, CustomField, FollowUp -from .lib import format_time_spent +from .models import Ticket, CustomField, FollowUp, FollowUpAttachment +from .lib import format_time_spent, process_attachments from .user import HelpdeskUser @@ -71,22 +71,44 @@ class DatatablesTicketSerializer(serializers.ModelSerializer): return obj.kbitem.title if obj.kbitem else "" +class FollowUpAttachmentSerializer(serializers.ModelSerializer): + class Meta: + model = FollowUpAttachment + fields = ('id', 'followup', 'file', 'filename', 'mime_type', 'size') + + class FollowUpSerializer(serializers.ModelSerializer): + followupattachment_set = FollowUpAttachmentSerializer(many=True, read_only=True) + attachments = serializers.ListField( + child=serializers.FileField(), + write_only=True, + required=False + ) + class Meta: model = FollowUp fields = ( - 'id', 'ticket', 'date', 'title', 'comment', 'public', 'user', 'new_status', 'message_id', 'time_spent' + 'id', 'ticket', 'date', 'title', 'comment', 'public', 'user', 'new_status', 'message_id', + 'time_spent', 'followupattachment_set', 'attachments' ) + def create(self, validated_data): + attachments = validated_data.pop('attachments', None) + followup = super().create(validated_data) + if attachments: + process_attachments(followup, attachments) + return followup + class TicketSerializer(serializers.ModelSerializer): followup_set = FollowUpSerializer(many=True, read_only=True) + attachment = serializers.FileField(write_only=True, required=False) class Meta: model = Ticket fields = ( 'id', 'queue', 'title', 'description', 'resolution', 'submitter_email', 'assigned_to', 'status', 'on_hold', - 'priority', 'due_date', 'merged_to', 'followup_set' + 'priority', 'due_date', 'merged_to', 'attachment', 'followup_set' ) def __init__(self, *args, **kwargs): @@ -109,7 +131,9 @@ class TicketSerializer(serializers.ModelSerializer): if data.get('merged_to'): data['merged_to'] = data['merged_to'].id - ticket_form = TicketForm(data=data, queue_choices=queue_choices) + files = {'attachment': data.pop('attachment', None)} + + ticket_form = TicketForm(data=data, files=files, queue_choices=queue_choices) if ticket_form.is_valid(): ticket = ticket_form.save(user=self.context['request'].user) ticket.set_custom_field_values() diff --git a/helpdesk/urls.py b/helpdesk/urls.py index 4079fb28..b87a89a4 100644 --- a/helpdesk/urls.py +++ b/helpdesk/urls.py @@ -17,7 +17,7 @@ from rest_framework.routers import DefaultRouter from helpdesk.decorators import helpdesk_staff_member_required, protect_view from helpdesk.views import feeds, staff, public, login from helpdesk import settings as helpdesk_settings -from helpdesk.views.api import TicketViewSet, CreateUserView, FollowUpViewSet +from helpdesk.views.api import TicketViewSet, CreateUserView, FollowUpViewSet, FollowUpAttachmentViewSet if helpdesk_settings.HELPDESK_KB_ENABLED: from helpdesk.views import kb @@ -177,6 +177,7 @@ if helpdesk_settings.HELPDESK_ACTIVATE_API_ENDPOINT: router = DefaultRouter() router.register(r"tickets", TicketViewSet, basename="ticket") router.register(r"followups", FollowUpViewSet, basename="followups") + router.register(r"followups-attachments", FollowUpAttachmentViewSet, basename="followupattachments") router.register(r"users", CreateUserView, basename="user") urlpatterns += [re_path(r"^api/", include(router.urls))] diff --git a/helpdesk/views/api.py b/helpdesk/views/api.py index a77514a2..d217a1a4 100644 --- a/helpdesk/views/api.py +++ b/helpdesk/views/api.py @@ -4,8 +4,8 @@ from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import CreateModelMixin from django.contrib.auth import get_user_model -from helpdesk.models import Ticket, FollowUp -from helpdesk.serializers import TicketSerializer, UserSerializer, FollowUpSerializer +from helpdesk.models import Ticket, FollowUp, FollowUpAttachment +from helpdesk.serializers import TicketSerializer, UserSerializer, FollowUpSerializer, FollowUpAttachmentSerializer class TicketViewSet(viewsets.ModelViewSet): @@ -29,14 +29,17 @@ class TicketViewSet(viewsets.ModelViewSet): class FollowUpViewSet(viewsets.ModelViewSet): - """ - A viewset that provides the standard actions to handle FollowUp - """ queryset = FollowUp.objects.all() serializer_class = FollowUpSerializer permission_classes = [IsAdminUser] +class FollowUpAttachmentViewSet(viewsets.ModelViewSet): + queryset = FollowUpAttachment.objects.all() + serializer_class = FollowUpAttachmentSerializer + permission_classes = [IsAdminUser] + + class CreateUserView(CreateModelMixin, GenericViewSet): queryset = get_user_model().objects.all() serializer_class = UserSerializer From c15c623205767e5b98e03a04dc894872d757b32e Mon Sep 17 00:00:00 2001 From: bbrendon Date: Sat, 25 Jun 2022 15:09:14 -0700 Subject: [PATCH 03/12] update install for noobs like me --- docs/install.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install.rst b/docs/install.rst index 3fd64a3a..743d34e8 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -74,11 +74,12 @@ errors with trying to create User settings. SITE_ID = 1 -2. Make sure django-helpdesk is accessible via ``urls.py``. Add the following line to ``urls.py``:: +2. Make sure django-helpdesk is accessible via ``urls.py``. Add the following lines to ``urls.py``:: + from django.conf.urls import include path('helpdesk/', include('helpdesk.urls')), - Note that you can change 'helpdesk/' to anything you like, such as 'support/' or 'help/'. If you want django-helpdesk to be available at the root of your site (for example at http://support.mysite.tld/) then the line will be as follows:: + Note that you can change 'helpdesk/' to anything you like, such as 'support/' or 'help/'. If you want django-helpdesk to be available at the root of your site (for example at http://support.mysite.tld/) then the path line will be as follows:: path('', include('helpdesk.urls', namespace='helpdesk')), From e47170858e08d8b83b3e65eb82727c5b030fe845 Mon Sep 17 00:00:00 2001 From: Benbb96 Date: Thu, 30 Jun 2022 23:43:22 +0200 Subject: [PATCH 04/12] Create two new tests for ticket followups and followup attachments + adapt one test (needed to use freezegun) --- helpdesk/tests/test_api.py | 71 +++++++++++++++++++++++++++++++++++++- requirements-testing.txt | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/helpdesk/tests/test_api.py b/helpdesk/tests/test_api.py index 0a0dedfe..ab9a146c 100644 --- a/helpdesk/tests/test_api.py +++ b/helpdesk/tests/test_api.py @@ -1,8 +1,11 @@ import base64 +from collections import OrderedDict from datetime import datetime +from django.core.files.uploadedfile import SimpleUploadedFile +from freezegun import freeze_time + from django.contrib.auth.models import User -from pytz import UTC from rest_framework import HTTP_HEADER_ENCODING from rest_framework.exceptions import ErrorDetail from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN @@ -72,6 +75,7 @@ class TicketTest(APITestCase): self.assertEqual(created_ticket.description, 'Test description\nMulti lines') self.assertEqual(created_ticket.submitter_email, 'test@mail.com') self.assertEqual(created_ticket.priority, 4) + self.assertEqual(created_ticket.followup_set.count(), 1) def test_create_api_ticket_with_basic_auth(self): username = 'admin' @@ -178,6 +182,7 @@ class TicketTest(APITestCase): self.assertEqual(response.status_code, HTTP_204_NO_CONTENT) self.assertFalse(Ticket.objects.exists()) + @freeze_time('2022-06-30 23:09:44') def test_create_api_ticket_with_custom_fields(self): # Create custom fields for field_type, field_display in CustomField.DATA_TYPE_CHOICES: @@ -247,6 +252,19 @@ class TicketTest(APITestCase): 'priority': 4, 'due_date': None, 'merged_to': None, + 'followup_set': [OrderedDict([ + ('id', 1), + ('ticket', 1), + ('date', '2022-06-30T23:09:44'), + ('title', 'Ticket Opened'), + ('comment', 'Test description\nMulti lines'), + ('public', True), + ('user', 1), + ('new_status', None), + ('message_id', None), + ('time_spent', None), + ('followupattachment_set', []) + ])], 'custom_varchar': 'test', 'custom_text': 'multi\nline', 'custom_integer': 1, @@ -262,3 +280,54 @@ class TicketTest(APITestCase): 'custom_slug': 'test-slug' }) + def test_create_api_ticket_with_attachment(self): + staff_user = User.objects.create_user(username='test', is_staff=True) + self.client.force_authenticate(staff_user) + test_file = SimpleUploadedFile('file.jpg', b'file_content', content_type='image/jpg') + response = self.client.post('/api/tickets/', { + 'queue': self.queue.id, + 'title': 'Test title', + 'description': 'Test description\nMulti lines', + 'submitter_email': 'test@mail.com', + 'priority': 4, + 'attachment': test_file + }) + self.assertEqual(response.status_code, HTTP_201_CREATED) + created_ticket = Ticket.objects.get() + self.assertEqual(created_ticket.title, 'Test title') + self.assertEqual(created_ticket.description, 'Test description\nMulti lines') + self.assertEqual(created_ticket.submitter_email, 'test@mail.com') + self.assertEqual(created_ticket.priority, 4) + self.assertEqual(created_ticket.followup_set.count(), 1) + self.assertEqual(created_ticket.followup_set.get().followupattachment_set.count(), 1) + attachment = created_ticket.followup_set.get().followupattachment_set.get() + self.assertEqual( + attachment.file.name, + f'helpdesk/attachments/test-queue-1-{created_ticket.secret_key}/1/file.jpg' + ) + + def test_create_follow_up_with_attachments(self): + staff_user = User.objects.create_user(username='test', is_staff=True) + self.client.force_authenticate(staff_user) + ticket = Ticket.objects.create(queue=self.queue, title='Test') + test_file_1 = SimpleUploadedFile('file.jpg', b'file_content', content_type='image/jpg') + test_file_2 = SimpleUploadedFile('doc.pdf', b'Doc content', content_type='application/pdf') + + response = self.client.post('/api/followups/', { + 'ticket': ticket.id, + 'title': 'Test', + 'comment': 'Test answer\nMulti lines', + 'attachments': [ + test_file_1, + test_file_2 + ] + }) + self.assertEqual(response.status_code, HTTP_201_CREATED) + created_followup = ticket.followup_set.last() + self.assertEqual(created_followup.title, 'Test') + self.assertEqual(created_followup.comment, 'Test answer\nMulti lines') + self.assertEqual(created_followup.followupattachment_set.count(), 2) + self.assertEqual(created_followup.followupattachment_set.first().filename, 'doc.pdf') + self.assertEqual(created_followup.followupattachment_set.first().mime_type, 'application/pdf') + self.assertEqual(created_followup.followupattachment_set.last().filename, 'file.jpg') + self.assertEqual(created_followup.followupattachment_set.last().mime_type, 'image/jpg') diff --git a/requirements-testing.txt b/requirements-testing.txt index db93a92f..c07a8ced 100644 --- a/requirements-testing.txt +++ b/requirements-testing.txt @@ -5,3 +5,4 @@ coverage argparse pbr mock +freezegun From 2e3f544cd8ae201a9d5805ae1fdf94fc23b016c8 Mon Sep 17 00:00:00 2001 From: Benbb96 Date: Fri, 1 Jul 2022 00:00:34 +0200 Subject: [PATCH 05/12] Update API documentation --- docs/api.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/api.rst b/docs/api.rst index 234d4a5b..679bccad 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -46,6 +46,33 @@ Here is an example of a cURL request to create a ticket (using Basic authenticat --header 'Content-Type: application/json' \ --data-raw '{"queue": 1, "title": "Test Ticket API", "description": "Test create ticket from API", "submitter_email": "test@mail.com", "priority": 4}' +Note that you can attach one file as attachment but in this case, you cannot use JSON for the request content type. Here is an example with form-data (curl default) :: + + curl --location --request POST 'http://127.0.0.1:8000/api/tickets/' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --form 'queue="1"' \ + --form 'title="Test Ticket API with attachment"' \ + --form 'description="Test create ticket from API avec attachment"' \ + --form 'submitter_email="test@mail.com"' \ + --form 'priority="2"' \ + --form 'attachment=@"/C:/Users/benbb96/Documents/file.txt"' + +---- + +Accessing the endpoint ``/api/followups/`` with a **POST** request will let you create a new followup on a ticket. + +This time, you can attach multiple files thanks to the `attachments` field. Here is an example :: + + curl --location --request POST 'http://127.0.0.1:8000/api/followups/' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --form 'ticket="44"' \ + --form 'title="Test ticket answer"' \ + --form 'comment="This answer contains multiple files as attachment."' \ + --form 'attachments=@"/C:/Users/benbb96/Documents/doc.pdf"' \ + --form 'attachments=@"/C:/Users/benbb96/Documents/image.png"' + +---- + Accessing the endpoint ``/api/users/`` with a **POST** request will let you create a new user. You need to provide a JSON body with the following data : From a0be579091fbe71f985ab458fa374d297393be96 Mon Sep 17 00:00:00 2001 From: Benbb96 Date: Fri, 1 Jul 2022 00:04:31 +0200 Subject: [PATCH 06/12] Add more information + Reformat documentation --- docs/api.rst | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 679bccad..77e4b587 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,20 +1,25 @@ API === -A REST API (built with ``djangorestframework``) is available in order to list, create, update and delete tickets from other tools thanks to HTTP requests. +A REST API (built with ``djangorestframework``) is available in order to list, create, update and delete tickets from +other tools thanks to HTTP requests. If you wish to use it, you have to add this line in your settings:: HELPDESK_ACTIVATE_API_ENDPOINT = True -You must be authenticated to access the API, the URL endpoint is ``/api/tickets/``. You can configure how you wish to authenticate to the API by customizing the ``DEFAULT_AUTHENTICATION_CLASSES`` key in the ``REST_FRAMEWORK`` setting (more information on this page : https://www.django-rest-framework.org/api-guide/authentication/) +You must be authenticated to access the API, the URL endpoint is ``/api/tickets/``. +You can configure how you wish to authenticate to the API by customizing the ``DEFAULT_AUTHENTICATION_CLASSES`` key +in the ``REST_FRAMEWORK`` setting (more information on this page : https://www.django-rest-framework.org/api-guide/authentication/) GET --- -Accessing the endpoint ``/api/tickets/`` with a **GET** request will return you the complete list of tickets. +Accessing the endpoint ``/api/tickets/`` with a **GET** request will return you the complete list of tickets with their +followups and their attachment files. -Accessing the endpoint ``/api/tickets/`` with a **GET** request will return you the data of the ticket you provided the ID. +Accessing the endpoint ``/api/tickets/`` with a **GET** request will return you the data of the ticket you +provided the ID. POST ---- @@ -35,7 +40,8 @@ You need to provide a JSON body with the following data : - **due_date**: date representation for when the ticket is due - **merged_to**: ID of the ticket to which it is merged -Note that ``status`` will automatically be set to OPEN. Also, some fields are not configurable during creation: ``resolution``, ``on_hold`` and ``merged_to``. +Note that ``status`` will automatically be set to OPEN. Also, some fields are not configurable during creation: +``resolution``, ``on_hold`` and ``merged_to``. Moreover, if you created custom fields, you can add them into the body with the key ``custom_``. @@ -46,7 +52,8 @@ Here is an example of a cURL request to create a ticket (using Basic authenticat --header 'Content-Type: application/json' \ --data-raw '{"queue": 1, "title": "Test Ticket API", "description": "Test create ticket from API", "submitter_email": "test@mail.com", "priority": 4}' -Note that you can attach one file as attachment but in this case, you cannot use JSON for the request content type. Here is an example with form-data (curl default) :: +Note that you can attach one file as attachment but in this case, you cannot use JSON for the request content type. +Here is an example with form-data (curl default) :: curl --location --request POST 'http://127.0.0.1:8000/api/tickets/' \ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ @@ -86,18 +93,21 @@ You need to provide a JSON body with the following data : PUT --- -Accessing the endpoint ``/api/tickets/`` with a **PUT** request will let you update the data of the ticket you provided the ID. +Accessing the endpoint ``/api/tickets/`` with a **PUT** request will let you update the data of the ticket +you provided the ID. You must include all fields in the JSON body. PATCH ----- -Accessing the endpoint ``/api/tickets/`` with a **PATCH** request will let you do a partial update of the data of the ticket you provided the ID. +Accessing the endpoint ``/api/tickets/`` with a **PATCH** request will let you do a partial update of the +data of the ticket you provided the ID. You can include only the fields you need to update in the JSON body. DELETE ------ -Accessing the endpoint ``/api/tickets/`` with a **DELETE** request will let you delete the ticket you provided the ID. +Accessing the endpoint ``/api/tickets/`` with a **DELETE** request will let you delete the ticket you +provided the ID. From de39b9847cbd7d9ac5bb89cac99857bcd85d40d7 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:22:40 -0400 Subject: [PATCH 07/12] Azure pipelines config update Add testing dependencies to azure pipelines config --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 771a7f04..8db0bbdb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -56,6 +56,7 @@ steps: - script: | python -m pip install --upgrade pip setuptools wheel pip install -c constraints-Django$(DJANGO_VERSION).txt -r requirements.txt + pip install -c constraints-Django$(DJANGO_VERSION).txt -r requirements-testing.txt pip install unittest-xml-reporting displayName: 'Install prerequisites' From 8e8a5f2d30a8ece7a0072002b24492519bb5187c Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:25:41 -0400 Subject: [PATCH 08/12] Create constraints-Django4 --- constraints-Django4 | 1 + 1 file changed, 1 insertion(+) create mode 100644 constraints-Django4 diff --git a/constraints-Django4 b/constraints-Django4 new file mode 100644 index 00000000..1643cbe5 --- /dev/null +++ b/constraints-Django4 @@ -0,0 +1 @@ +Django >=4,<5 From 4abc0f3418489e0fbd45ead73e42759f801da413 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:27:13 -0400 Subject: [PATCH 09/12] Do testing with Django 4 and Python 3.10 --- azure-pipelines.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8db0bbdb..2cc53fdd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,18 +17,24 @@ pool: vmImage: ubuntu-latest strategy: matrix: - Python38Django22: - PYTHON_VERSION: '3.8' - DJANGO_VERSION: '22' - Python39Django22: - PYTHON_VERSION: '3.9' - DJANGO_VERSION: '22' Python38Django32: PYTHON_VERSION: '3.8' DJANGO_VERSION: '32' Python39Django32: PYTHON_VERSION: '3.9' DJANGO_VERSION: '32' + Python310Django32: + PYTHON_VERSION: '3.10' + DJANGO_VERSION: '32' + Python38Django4: + PYTHON_VERSION: '3.8' + DJANGO_VERSION: '4' + Python39Django4: + PYTHON_VERSION: '3.9' + DJANGO_VERSION: '4' + Python310Django4: + PYTHON_VERSION: '3.10' + DJANGO_VERSION: '4' maxParallel: 10 steps: From 50835e6b51a19d68e02900db0adf45e6b9e7e0fe Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:33:56 -0400 Subject: [PATCH 10/12] Rename constraints-Django4 to constraints-Django4.txt --- constraints-Django4 => constraints-Django4.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename constraints-Django4 => constraints-Django4.txt (100%) diff --git a/constraints-Django4 b/constraints-Django4.txt similarity index 100% rename from constraints-Django4 rename to constraints-Django4.txt From 4f4f2c56876a6999217b9080040d50c768121398 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:34:23 -0400 Subject: [PATCH 11/12] Delete constraints-Django22.txt --- constraints-Django22.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 constraints-Django22.txt diff --git a/constraints-Django22.txt b/constraints-Django22.txt deleted file mode 100644 index 1a728bf4..00000000 --- a/constraints-Django22.txt +++ /dev/null @@ -1,2 +0,0 @@ -Django >=2.2,<3 - From fbf022df963285748d88fbde92027508690c054c Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Sat, 2 Jul 2022 06:40:35 -0400 Subject: [PATCH 12/12] Bump to version 0.4.1 --- README.rst | 2 +- demo/setup.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 9d9ab777..d7cb3237 100644 --- a/README.rst +++ b/README.rst @@ -6,7 +6,7 @@ django-helpdesk - A Django powered ticket tracker for small businesses. .. image:: https://codecov.io/gh/django-helpdesk/django-helpdesk/branch/develop/graph/badge.svg :target: https://codecov.io/gh/django-helpdesk/django-helpdesk -Copyright 2009-2021 Ross Poulton and django-helpdesk contributors. All Rights Reserved. +Copyright 2009-2022 Ross Poulton and django-helpdesk contributors. All Rights Reserved. See LICENSE for details. django-helpdesk was formerly known as Jutda Helpdesk, named after the diff --git a/demo/setup.py b/demo/setup.py index 463a15e0..01c009bf 100644 --- a/demo/setup.py +++ b/demo/setup.py @@ -13,7 +13,7 @@ project_root = os.path.dirname(here) NAME = 'django-helpdesk-demodesk' DESCRIPTION = 'A demo Django project using django-helpdesk' README = open(os.path.join(here, 'README.rst')).read() -VERSION = '0.4.0' +VERSION = '0.4.1' #VERSION = open(os.path.join(project_root, 'VERSION')).read().strip() AUTHOR = 'django-helpdesk team' URL = 'https://github.com/django-helpdesk/django-helpdesk' diff --git a/setup.py b/setup.py index 3b71a534..4ea2cd46 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.util import convert_path from fnmatch import fnmatchcase from setuptools import setup, find_packages -version = '0.4.0' +version = '0.4.1' # Provided as an attribute, so you can append to these instead # of replicating them: