diff --git a/app/api/tests/functional/test_functional_api_fields.py b/app/api/tests/functional/test_functional_api_fields.py index c2d60117..ccef108d 100644 --- a/app/api/tests/functional/test_functional_api_fields.py +++ b/app/api/tests/functional/test_functional_api_fields.py @@ -184,7 +184,10 @@ class APIFieldsTestCases: view_team.delete() - request.cls.view_user.delete() + try: + request.cls.view_user.delete() + except django.db.models.deletion.ProtectedError: + pass del request.cls.kwargs_create_item diff --git a/app/core/models/ticket_base.py b/app/core/models/ticket_base.py index 0b46637c..fd6a9f05 100644 --- a/app/core/models/ticket_base.py +++ b/app/core/models/ticket_base.py @@ -48,7 +48,7 @@ class TicketBase( save_model_history: bool = False - url_model_name = 'ticket' + url_model_name = 'ticketbase' class Ticket_ExternalSystem(models.IntegerChoices): # GITHUB = TicketValues.ExternalSystem._GITHUB_INT, TicketValues.ExternalSystem._GITHUB_VALUE @@ -831,6 +831,35 @@ class TicketBase( return related_model + + def get_url_kwargs(self, many = False) -> dict: + """Get URL Kwargs + + Fecth the kwargs required for building a models URL using the reverse + method. + + **Note:** It's advisable that if you override this function, that you + call it's super, so as not to duplicate code. That way each override + builds up[on the parent `get_url_kwargs` function. + + Returns: + dict: Kwargs required for reverse function to build a models URL. + """ + + kwargs = super().get_url_kwargs( many = many ) + + if self._is_submodel: + + del kwargs['model_name'] + + kwargs.update({ + 'ticket_type': str(self._meta.sub_model_type), + }) + + return kwargs + + + def create_action_comment(self) -> None: from core.models.ticket_comment_action import TicketCommentAction diff --git a/app/core/tests/functional/ticket_base/test_functional_ticket_base_metadata.py b/app/core/tests/functional/ticket_base/test_functional_ticket_base_metadata.py index 8757a3b1..a6533ca1 100644 --- a/app/core/tests/functional/ticket_base/test_functional_ticket_base_metadata.py +++ b/app/core/tests/functional/ticket_base/test_functional_ticket_base_metadata.py @@ -243,7 +243,7 @@ class TicketBaseMetadataInheritedCases( kwargs_create_item_diff_org: dict = {} - url_name = '_api_ticket_sub' + url_name = '_api_ticketbase_sub' @classmethod @@ -260,11 +260,11 @@ class TicketBaseMetadataInheritedCases( } self.url_kwargs = { - 'model_name': self.model._meta.sub_model_type + 'ticket_type': self.model._meta.sub_model_type } self.url_view_kwargs = { - 'model_name': self.model._meta.sub_model_type + 'ticket_type': self.model._meta.sub_model_type } super().setUpTestData() @@ -277,7 +277,7 @@ class TicketBaseMetadataTest( ): - url_name = '_api_v2_ticket' + url_name = '_api_ticketbase' # def test_method_options_request_detail_data_has_key_urls_back(self): diff --git a/app/core/tests/functional/ticket_base/test_functional_ticket_base_permission.py b/app/core/tests/functional/ticket_base/test_functional_ticket_base_permission.py deleted file mode 100644 index 6aabfaaf..00000000 --- a/app/core/tests/functional/ticket_base/test_functional_ticket_base_permission.py +++ /dev/null @@ -1,133 +0,0 @@ -import pytest - -from api.tests.functional.test_functional_api_permissions import ( - APIPermissionsInheritedCases, -) - - - -@pytest.mark.model_ticketbase -class PermissionsAPITestCases( - APIPermissionsInheritedCases, -): - - add_data: dict = { - 'title': 'ticket one', - 'description': 'sadsa' - } - - app_namespace = 'v2' - - change_data = {'description': 'device'} - - delete_data = {} - - kwargs_create_item: dict = { - 'title': 'ticket two', - 'description': 'sadsa' - } - - kwargs_create_item_diff_org: dict = { - 'title': 'ticket three', - 'description': 'sadsa' - } - - url_kwargs: dict = {} - - url_name = '_api_v2_ticket' - - url_view_kwargs: dict = {} - - - - - @pytest.fixture(scope='class') - def opened_by_var_setup(self, request): - - request.cls.kwargs_create_item.update({ - 'opened_by': request.cls.view_user - }) - - request.cls.kwargs_create_item_diff_org.update({ - 'opened_by': request.cls.view_user - }) - - if request.cls.add_data is not None: - - request.cls.add_data.update({ - 'opened_by': request.cls.view_user.pk - }) - - - - @pytest.fixture(scope='class', autouse = True) - def class_setup(self, request, django_db_blocker, - model, - var_setup, - prepare, - opened_by_var_setup, - diff_org_model, - create_model, - post_model - ): - - pass - - - - def test_returned_data_from_user_and_global_organizations_only(self): - """Check items returned - - This test case is a over-ride of a test case with the same name. - This model is not a tenancy model making this test not-applicable. - - Items returned from the query Must be from the users organization and - global ONLY! - """ - pass - - - -class TicketBasePermissionsAPIInheritedCases( - PermissionsAPITestCases, -): - - add_data: dict = None - - kwargs_create_item: dict = None - - kwargs_create_item_diff_org: dict = None - - - @pytest.fixture(scope='class') - def inherited_var_setup(self, request): - - request.cls.url_kwargs.update({ - 'model_name': self.model._meta.sub_model_type - }) - - request.cls.url_view_kwargs.update({ - 'model_name': self.model._meta.sub_model_type - }) - - - - @pytest.fixture(scope='class', autouse = True) - def class_setup(self, request, django_db_blocker, - model, - var_setup, - prepare, - opened_by_var_setup, - inherited_var_setup, - diff_org_model, - create_model, - ): - - pass - -@pytest.mark.module_core -class TicketBasePermissionsAPIPyTest( - PermissionsAPITestCases, -): - - pass diff --git a/app/core/tests/functional/ticket_base/test_functional_ticket_base_serializer.py b/app/core/tests/functional/ticket_base/test_functional_ticket_base_serializer.py index fac29584..5f11d172 100644 --- a/app/core/tests/functional/ticket_base/test_functional_ticket_base_serializer.py +++ b/app/core/tests/functional/ticket_base/test_functional_ticket_base_serializer.py @@ -207,7 +207,10 @@ class TicketBaseSerializerTestCases: with django_db_blocker.unblock(): - request.cls.view_user.delete() + try: + request.cls.view_user.delete() + except django.db.models.deletion.ProtectedError: + pass request.cls.other_user.delete() del request.cls.valid_data diff --git a/app/core/tests/functional/ticket_base/test_functional_ticket_base_viewset.py b/app/core/tests/functional/ticket_base/test_functional_ticket_base_viewset.py index e33a710c..57b72299 100644 --- a/app/core/tests/functional/ticket_base/test_functional_ticket_base_viewset.py +++ b/app/core/tests/functional/ticket_base/test_functional_ticket_base_viewset.py @@ -93,7 +93,8 @@ class ViewSetBase: ) - self.url_view_kwargs.update({'model_name': self.item._meta.model_name, 'pk': self.item.id }) + # self.url_view_kwargs.update({'ticket_type': self.item._meta.sub_model_type, 'pk': self.item.id }) + self.url_view_kwargs.update({'pk': self.item.id }) if self.add_data is not None: @@ -250,7 +251,7 @@ class TicketBaseViewSetInheritedCases( # kwargs_create_item_diff_org: dict = {} - url_name = '_api_ticket_sub' + url_name = '_api_ticketbase_sub' @classmethod @@ -267,11 +268,11 @@ class TicketBaseViewSetInheritedCases( } self.url_kwargs = { - 'model_name': self.model._meta.model_name + 'ticket_type': self.model._meta.sub_model_type } self.url_view_kwargs = { - 'model_name': self.model._meta.model_name + 'ticket_type': self.model._meta.sub_model_type } super().setUpTestData() @@ -283,4 +284,4 @@ class TicketBaseViewSetTest( TestCase, ): - url_name = '_api_v2_ticket' + url_name = '_api_ticketbase' diff --git a/app/core/tests/unit/ticket_base/test_unit_ticket_base_api_fields.py b/app/core/tests/unit/ticket_base/test_unit_ticket_base_api_fields.py index b747ddb5..fa353788 100644 --- a/app/core/tests/unit/ticket_base/test_unit_ticket_base_api_fields.py +++ b/app/core/tests/unit/ticket_base/test_unit_ticket_base_api_fields.py @@ -1,3 +1,4 @@ +import django import pytest from rest_framework.relations import Hyperlink @@ -67,10 +68,10 @@ class APITestCases( }) - if request.cls.model._meta.model_name != 'ticketbase': + if request.cls.model._meta.sub_model_type != 'ticket': request.cls.url_view_kwargs.update({ - 'model_name': str(request.cls.model._meta.sub_model_type), + 'ticket_type': str(request.cls.model._meta.sub_model_type), }) yield @@ -81,15 +82,24 @@ class APITestCases( parent_ticket.delete() - project_milestone.delete() + try: + project_milestone.delete() + except django.db.models.deletion.ProtectedError: + pass - project.delete() + try: + project.delete() + except django.db.models.deletion.ProtectedError: + pass - request.cls.kwargs_create_item['category'].delete() + try: + request.cls.kwargs_create_item['category'].delete() + except django.db.models.deletion.ProtectedError: + pass - if 'model_name' in request.cls.url_view_kwargs: + if 'ticket_type' in request.cls.url_view_kwargs: - del request.cls.url_view_kwargs['model_name'] + del request.cls.url_view_kwargs['ticket_type'] @@ -386,7 +396,7 @@ class APITestCases( 'date_closed': '2025-05-12T02:30:02', } - url_ns_name = '_api_v2_ticket' + url_ns_name = '_api_ticketbase' """Url namespace (optional, if not required) and url name""" @@ -411,7 +421,7 @@ class TicketBaseAPIInheritedCases( model = None - url_ns_name = '_api_ticket_sub' + url_ns_name = '_api_ticketbase_sub' @pytest.mark.module_core diff --git a/app/core/tests/unit/ticket_base/test_unit_ticket_base_model.py b/app/core/tests/unit/ticket_base/test_unit_ticket_base_model.py index 3cecd4fe..e53ff947 100644 --- a/app/core/tests/unit/ticket_base/test_unit_ticket_base_model.py +++ b/app/core/tests/unit/ticket_base/test_unit_ticket_base_model.py @@ -36,7 +36,7 @@ class TicketBaseModelTestCases( }, 'url_model_name': { 'type': str, - 'value': 'ticket' + 'value': 'ticketbase' }, } @@ -487,8 +487,12 @@ class TicketBaseModelTestCases( model_ticketcommentbase, kwargs_ticketcommentbase ): + kwargs = kwargs_ticketcommentbase.copy() + del kwargs['ticket'] + + comment = model_ticketcommentbase.objects.create( - **kwargs_ticketcommentbase, + **kwargs, ticket = ticket, ) diff --git a/app/core/tests/unit/ticket_base/test_unit_ticket_base_viewset.py b/app/core/tests/unit/ticket_base/test_unit_ticket_base_viewset.py index a5e27e1d..301950dc 100644 --- a/app/core/tests/unit/ticket_base/test_unit_ticket_base_viewset.py +++ b/app/core/tests/unit/ticket_base/test_unit_ticket_base_viewset.py @@ -45,7 +45,7 @@ class ViewsetTestCases( if self.model != TicketBase: self.kwargs = { - 'model_name': self.model._meta.model_name + 'ticket_type': self.model._meta.sub_model_type } self.viewset.kwargs = self.kwargs @@ -73,7 +73,7 @@ class ViewsetTestCases( view_set = self.viewset() - assert view_set.model_kwarg == 'model_name' + assert view_set.model_kwarg == 'ticket_type' @@ -88,7 +88,7 @@ class TicketBaseViewsetInheritedCases( model: str = None """name of the model to test""" - route_name = 'v2:_api_ticket_sub' + route_name = 'v2:_api_ticketbase_sub' @pytest.mark.module_core @@ -97,6 +97,6 @@ class TicketBaseViewsetTest( TestCase, ): - route_name = 'v2:_api_v2_ticket' + route_name = 'v2:_api_ticketbase' viewset = NoDocsViewSet diff --git a/app/core/urls_api.py b/app/core/urls_api.py index 0f1ed47a..75cc27ba 100644 --- a/app/core/urls_api.py +++ b/app/core/urls_api.py @@ -21,7 +21,7 @@ for model in apps.get_models(): if issubclass(model, ticket.TicketBase): - ticket_type_names += model._meta.model_name + '|' + ticket_type_names += model._meta.sub_model_type + '|' if issubclass(model, ticket_comment.TicketCommentBase): @@ -48,16 +48,12 @@ router.register( router.register( - prefix=f'ticket', viewset = ticket.ViewSet, - feature_flag = '2025-00006', basename = '_api_ticket' + prefix=f'ticket', viewset = ticket.NoDocsViewSet, + feature_flag = '2025-00006', basename = '_api_ticketbase' ) router.register( - prefix=f'ticket/(?P[{ticket_type_names}]+)', viewset = ticket.ViewSet, - feature_flag = '2025-00006', basename = '_api_ticket_sub' -) -router.register( - prefix = 'ticket', viewset = ticket.NoDocsViewSet, - basename = '_api_v2_ticket' + prefix=f'ticket/(?P[{ticket_type_names}]+)', viewset = ticket.ViewSet, + feature_flag = '2025-00006', basename = '_api_ticketbase_sub' ) router.register( prefix = 'ticket/(?P[0-9]+)/comment', viewset = ticket_comment.NoDocsViewSet, diff --git a/app/core/viewsets/ticket.py b/app/core/viewsets/ticket.py index ab48f486..52e55776 100644 --- a/app/core/viewsets/ticket.py +++ b/app/core/viewsets/ticket.py @@ -29,7 +29,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): serializer_name = 'ticket' - if model._meta.model_name != 'ticketbase': + if model._meta.sub_model_type != 'ticket': serializer_name += '_' + model._meta.sub_model_type @@ -53,7 +53,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): description='.', parameters = [ OpenApiParameter( - name = 'model_name', + name = 'ticket_type', description = 'Enter the Ticket type. This is the name of the Ticket sub-model.', location = OpenApiParameter.PATH, type = str, @@ -94,7 +94,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): description = '.', parameters =[ OpenApiParameter( - name = 'model_name', + name = 'ticket_type', description = 'Enter the ticket type. This is the name of the Ticket sub-model.', location = OpenApiParameter.PATH, type = str, @@ -118,7 +118,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): description='.', parameters = [ OpenApiParameter( - name = 'model_name', + name = 'ticket_type', description = 'Enter the ticket type. This is the name of the Ticket sub-model.', location = OpenApiParameter.PATH, type = str, @@ -150,7 +150,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): description='.', parameters = [ OpenApiParameter( - name = 'model_name', + name = 'ticket_type', description = 'Enter the ticket type. This is the name of the Ticket sub-model.', location = OpenApiParameter.PATH, type = str, @@ -183,7 +183,7 @@ def spectacular_request_serializers( serializer_type = 'Model'): description = '.', parameters = [ OpenApiParameter( - name = 'tickets_model', + name = 'tickets_type', description = 'Enter the ticket type. This is the name of the Ticket sub-model.', location = OpenApiParameter.PATH, type = str, @@ -238,7 +238,7 @@ class ViewSet( SubModelViewSet ): 'is_deleted' ] - model_kwarg = 'model_name' + model_kwarg = 'ticket_type' search_fields = [ 'title', @@ -257,10 +257,10 @@ class ViewSet( SubModelViewSet ): ): self.back_url = reverse( - viewname = '_api_ticket_sub-list', + viewname = '_api_ticketbase_sub-list', request = self.request, kwargs = { - 'model_name': self.kwargs[self.model_kwarg], + 'ticket_type': self.kwargs[self.model_kwarg], } ) diff --git a/app/tests/fixtures/model_kwarg_data.py b/app/tests/fixtures/model_kwarg_data.py index 8cf02338..026a4522 100644 --- a/app/tests/fixtures/model_kwarg_data.py +++ b/app/tests/fixtures/model_kwarg_data.py @@ -1,6 +1,8 @@ import datetime -from django.core.exceptions import ValidationError, ObjectDoesNotExist import pytest +import random + +from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.db import models @@ -21,9 +23,17 @@ def model_kwarg_data(): for field, value in model_kwargs.items(): + is_unique_together_field = False + if not hasattr(getattr(model, field), 'field'): continue + for unique_field in getattr(model, field).field.model._meta.unique_together: + + if field in unique_field and getattr(model, field).field.choices is None: + + is_unique_together_field = True + if isinstance(getattr(model, field).field, models.ManyToManyField): if isinstance(value, list): @@ -59,7 +69,10 @@ def model_kwarg_data(): continue elif( - getattr(model, field).field.unique + ( + getattr(model, field).field.unique + or is_unique_together_field + ) and not isinstance(getattr(model, field).field, models.UUIDField) and not isinstance(getattr(model, field).field, models.ForeignKey) @@ -69,7 +82,8 @@ def model_kwarg_data(): if isinstance(getattr(model, field).field, models.IntegerField): - value = str(random_str)[( len(random_str) - 13 ):] + # value = str(random_str)[( len(random_str) - 13 ):] + value = random.randint(1,999999) elif isinstance(getattr(model, field).field, models.EmailField): @@ -110,9 +124,9 @@ def model_kwarg_data(): no_modified_in_kwargs = kwargs.copy() del no_modified_in_kwargs['modified'] - instance = model.objects.get( - **no_modified_in_kwargs - ) + instance = model.objects.get( + **no_modified_in_kwargs + ) for field, values in many_field.items():