test(core): Serializer Validation for ticket status change for TicketBase model
ref: #734 #723
This commit is contained in:
@ -24,9 +24,11 @@ class OrganizationField(serializers.PrimaryKeyRelatedField):
|
||||
|
||||
if self.context.get('request', None):
|
||||
|
||||
if getattr(self.context['request'].app_settings, 'global_organization', None):
|
||||
if hasattr(self.context['request'], 'app_settings'):
|
||||
|
||||
queryset = queryset.exclude(id=self.context['request'].app_settings.global_organization.id)
|
||||
if getattr(self.context['request'].app_settings, 'global_organization', None):
|
||||
|
||||
queryset = queryset.exclude(id=self.context['request'].app_settings.global_organization.id)
|
||||
|
||||
return queryset
|
||||
|
||||
|
@ -278,12 +278,93 @@ class ModelSerializer(
|
||||
|
||||
def validate(self, attrs):
|
||||
|
||||
attrs = super().validate( attrs )
|
||||
|
||||
attrs = self.validate_field_milestone( attrs )
|
||||
|
||||
attrs = self.validate_field_external_system( attrs )
|
||||
|
||||
attrs = super().validate( attrs )
|
||||
|
||||
has_import_permission = self.context['view']._has_import
|
||||
|
||||
has_triage_permission = self.context['view']._has_triage
|
||||
|
||||
status = int(attrs.get('status', 0))
|
||||
|
||||
opened_by_id = int(attrs.get('opened_by_id', 0))
|
||||
|
||||
if self.context.get('request', None):
|
||||
|
||||
request_user_id = int(self.context['request'].user.id)
|
||||
|
||||
else:
|
||||
|
||||
request_user_id = 0
|
||||
|
||||
if opened_by_id == 0:
|
||||
|
||||
request_user_id = 0
|
||||
|
||||
if not (
|
||||
has_triage_permission
|
||||
or has_import_permission
|
||||
):
|
||||
|
||||
if(
|
||||
status == TicketBase.TicketStatus.ASSIGNED
|
||||
or status == TicketBase.TicketStatus.ASSIGNED_PLANNING
|
||||
):
|
||||
|
||||
raise centurion_exception.ValidationError(
|
||||
detail = {
|
||||
'status': 'You cant assign a ticket if you dont have permission triage'
|
||||
},
|
||||
code = 'no_triage_status_assigned',
|
||||
)
|
||||
|
||||
if status == TicketBase.TicketStatus.PENDING:
|
||||
|
||||
raise centurion_exception.ValidationError(
|
||||
detail = {
|
||||
'status': 'You cant set a ticket to pending if you dont have permission triage'
|
||||
},
|
||||
code = 'no_triage_status_pending',
|
||||
)
|
||||
|
||||
if(
|
||||
status == TicketBase.TicketStatus.SOLVED
|
||||
and opened_by_id != request_user_id
|
||||
):
|
||||
|
||||
raise centurion_exception.ValidationError(
|
||||
detail = {
|
||||
'status': 'You cant solve a ticket if you dont have permission triage'
|
||||
},
|
||||
code = 'no_triage_status_solve',
|
||||
)
|
||||
|
||||
if(
|
||||
status == TicketBase.TicketStatus.INVALID
|
||||
and opened_by_id != request_user_id
|
||||
):
|
||||
|
||||
raise centurion_exception.ValidationError(
|
||||
detail = {
|
||||
'status': 'You cant mark a ticket as invalid if you did not raise the ticket or you dont have permission triage'
|
||||
},
|
||||
code = 'no_triage_status_invalid',
|
||||
)
|
||||
|
||||
if status == TicketBase.TicketStatus.CLOSED:
|
||||
|
||||
raise centurion_exception.ValidationError(
|
||||
detail = {
|
||||
'status': 'You cant close a ticket if you dont have permission triage'
|
||||
},
|
||||
code = 'no_triage_status_close',
|
||||
)
|
||||
|
||||
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
|
@ -441,6 +441,286 @@ class TicketBaseSerializerTestCases:
|
||||
|
||||
|
||||
|
||||
values_validation_status_change_permission = [
|
||||
( 'own_ticket_no_import_triage_default_status', False, False, True, None, True ),
|
||||
|
||||
( 'own_ticket_no_import_triage_draft', False, False, True, TicketBase.TicketStatus.DRAFT, True ),
|
||||
( 'own_ticket_no_import_triage_new', False, False, True, TicketBase.TicketStatus.NEW, True ),
|
||||
( 'own_ticket_no_import_triage_assigned', False, False, True, TicketBase.TicketStatus.ASSIGNED, 'no_triage_status_assigned' ),
|
||||
( 'own_ticket_no_import_triage_assigned_planning', False, False, True, TicketBase.TicketStatus.ASSIGNED_PLANNING, 'no_triage_status_assigned' ),
|
||||
( 'own_ticket_no_import_triage_pending', False, False, True, TicketBase.TicketStatus.PENDING, 'no_triage_status_pending' ),
|
||||
( 'own_ticket_no_import_triage_solved', False, False, True, TicketBase.TicketStatus.SOLVED, True ),
|
||||
( 'own_ticket_no_import_triage_invalid', False, False, True, TicketBase.TicketStatus.INVALID, True ),
|
||||
( 'own_ticket_no_import_triage_closed', False, False, True, TicketBase.TicketStatus.CLOSED, 'no_triage_status_close' ),
|
||||
|
||||
( 'own_ticket_import_no_triage_default_status', True, False, True, None, True ),
|
||||
|
||||
( 'own_ticket_import_no_triage_draft', True, False, True, TicketBase.TicketStatus.DRAFT, True ),
|
||||
( 'own_ticket_import_no_triage_new', True, False, True, TicketBase.TicketStatus.NEW, True ),
|
||||
( 'own_ticket_import_no_triage_assigned', True, False, True, TicketBase.TicketStatus.ASSIGNED, True ),
|
||||
( 'own_ticket_import_no_triage_assigned_planning', True, False, True, TicketBase.TicketStatus.ASSIGNED_PLANNING, True ),
|
||||
( 'own_ticket_import_no_triage_pending', True, False, True, TicketBase.TicketStatus.PENDING, True ),
|
||||
( 'own_ticket_import_no_triage_solved', True, False, True, TicketBase.TicketStatus.SOLVED, True ),
|
||||
( 'own_ticket_import_no_triage_invalid', True, False, True, TicketBase.TicketStatus.INVALID, True ),
|
||||
( 'own_ticket_import_no_triage_closed', True, False, True, TicketBase.TicketStatus.CLOSED, True ),
|
||||
|
||||
( 'import_no_triage_default_status', True, False, False, None, True ),
|
||||
|
||||
( 'import_no_triage_draft', True, False, False, TicketBase.TicketStatus.DRAFT, True ),
|
||||
( 'import_no_triage_new', True, False, False, TicketBase.TicketStatus.NEW, True ),
|
||||
( 'import_no_triage_assigned', True, False, False, TicketBase.TicketStatus.ASSIGNED, True ),
|
||||
( 'import_no_triage_assigned_planning', True, False, False, TicketBase.TicketStatus.ASSIGNED_PLANNING, True ),
|
||||
( 'import_no_triage_pending', True, False, False, TicketBase.TicketStatus.PENDING, True ),
|
||||
( 'import_no_triage_solved', True, False, False, TicketBase.TicketStatus.SOLVED, True ),
|
||||
( 'import_no_triage_invalid', True, False, False, TicketBase.TicketStatus.INVALID, True ),
|
||||
( 'import_no_triage_closed', True, False, False, TicketBase.TicketStatus.CLOSED, True ),
|
||||
|
||||
( 'triage_no_import_default_status',False, True, False, None, True ),
|
||||
|
||||
( 'triage_no_import_draft', False, True, False, TicketBase.TicketStatus.DRAFT, True ),
|
||||
( 'triage_no_import_new', False, True, False, TicketBase.TicketStatus.NEW, True ),
|
||||
( 'triage_no_import_assigned', False, True, False, TicketBase.TicketStatus.ASSIGNED, True ),
|
||||
( 'triage_no_import_assigned_planning', False, True, False, TicketBase.TicketStatus.ASSIGNED_PLANNING, True ),
|
||||
( 'triage_no_import_pending', False, True, False, TicketBase.TicketStatus.PENDING, True ),
|
||||
( 'triage_no_import_solved', False, True, False, TicketBase.TicketStatus.SOLVED, True ),
|
||||
( 'triage_no_import_invalid', False, True, False, TicketBase.TicketStatus.INVALID, True ),
|
||||
( 'triage_no_import_closed', False, True, False, TicketBase.TicketStatus.CLOSED, True ),
|
||||
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames = [
|
||||
'name',
|
||||
'param_permission_import',
|
||||
'param_permission_triage',
|
||||
'param_is_owner',
|
||||
'status',
|
||||
'expected_result',
|
||||
],
|
||||
argvalues = values_validation_status_change_permission,
|
||||
ids = [
|
||||
name +'_'+ str(param_permission_import).lower() +'_'+ str(param_permission_triage).lower() +'_'+str(param_is_owner).lower() +'_'+str(status).lower() for
|
||||
name,
|
||||
param_permission_import,
|
||||
param_permission_triage,
|
||||
param_is_owner,
|
||||
status,
|
||||
expected_result,
|
||||
in values_validation_status_change_permission
|
||||
]
|
||||
)
|
||||
def test_serializer_create_validation_status(self,
|
||||
create_serializer,
|
||||
name,
|
||||
param_permission_import,
|
||||
param_permission_triage,
|
||||
param_is_owner,
|
||||
status,
|
||||
expected_result,
|
||||
):
|
||||
""" Test Serializer Validation for Status
|
||||
|
||||
When creating a ticket, ensure the user has the correct permissions
|
||||
to set the desired status
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
if status is None:
|
||||
|
||||
valid_data['status'] = TicketBase._meta.get_field('status').default
|
||||
|
||||
else:
|
||||
|
||||
valid_data['status'] = status
|
||||
|
||||
|
||||
view_set = MockView()
|
||||
|
||||
view_set._has_import = param_permission_import
|
||||
|
||||
view_set._has_triage = param_permission_triage
|
||||
|
||||
|
||||
class MockRequest:
|
||||
|
||||
class MockUser:
|
||||
|
||||
id = 999999
|
||||
|
||||
pk = 999999
|
||||
|
||||
user = MockUser()
|
||||
|
||||
mock_request = MockRequest()
|
||||
|
||||
if param_is_owner:
|
||||
|
||||
mock_request.user.id = self.view_user.pk
|
||||
|
||||
mock_request.user.pk = self.view_user.pk
|
||||
|
||||
|
||||
serializer = create_serializer(
|
||||
context = {
|
||||
'view': view_set,
|
||||
},
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.context['request'] = mock_request
|
||||
|
||||
if type(expected_result) is not bool:
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['status'][0] == expected_result
|
||||
|
||||
else:
|
||||
|
||||
assert serializer.is_valid(raise_exception = False) == expected_result
|
||||
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'function' )
|
||||
def existing_ticket(self, db, create_serializer):
|
||||
|
||||
view_set = MockView()
|
||||
|
||||
view_set._has_import = True
|
||||
|
||||
view_set._has_triage = True
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
valid_data['title'] = 'existing_ticket'
|
||||
|
||||
valid_data['status'] = TicketBase._meta.get_field('status').default
|
||||
|
||||
serializer = create_serializer(
|
||||
context = {
|
||||
'view': view_set,
|
||||
},
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = False)
|
||||
|
||||
serializer.save()
|
||||
|
||||
ticket = serializer.instance
|
||||
|
||||
yield ticket
|
||||
|
||||
if ticket.id:
|
||||
|
||||
ticket.delete()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames = [
|
||||
'name',
|
||||
'param_permission_import',
|
||||
'param_permission_triage',
|
||||
'param_is_owner',
|
||||
'status',
|
||||
'expected_result',
|
||||
],
|
||||
argvalues = values_validation_status_change_permission,
|
||||
ids = [
|
||||
name +'_'+ str(param_permission_import).lower() +'_'+ str(param_permission_triage).lower() +'_'+str(param_is_owner).lower() +'_'+str(status).lower() for
|
||||
name,
|
||||
param_permission_import,
|
||||
param_permission_triage,
|
||||
param_is_owner,
|
||||
status,
|
||||
expected_result,
|
||||
in values_validation_status_change_permission
|
||||
]
|
||||
)
|
||||
def test_serializer_update_validation_status(self,
|
||||
create_serializer,
|
||||
existing_ticket,
|
||||
name,
|
||||
param_permission_import,
|
||||
param_permission_triage,
|
||||
param_is_owner,
|
||||
status,
|
||||
expected_result,
|
||||
):
|
||||
""" Test Serializer Validation for Status
|
||||
|
||||
When updating a ticket, ensure the user has the correct permissions
|
||||
to set the desired status
|
||||
"""
|
||||
|
||||
valid_data = {
|
||||
'status': None
|
||||
}
|
||||
|
||||
if status is None:
|
||||
|
||||
valid_data['status'] = TicketBase._meta.get_field('status').default
|
||||
|
||||
else:
|
||||
|
||||
valid_data['status'] = status
|
||||
|
||||
|
||||
view_set = MockView()
|
||||
|
||||
view_set._has_import = param_permission_import
|
||||
|
||||
view_set._has_triage = param_permission_triage
|
||||
|
||||
|
||||
class MockRequest:
|
||||
|
||||
class MockUser:
|
||||
|
||||
id = 999999
|
||||
|
||||
pk = 999999
|
||||
|
||||
user = MockUser()
|
||||
|
||||
mock_request = MockRequest()
|
||||
|
||||
if param_is_owner:
|
||||
|
||||
mock_request.user.id = self.view_user.pk
|
||||
|
||||
mock_request.user.pk = self.view_user.pk
|
||||
|
||||
|
||||
serializer = create_serializer(
|
||||
instance = existing_ticket,
|
||||
context = {
|
||||
'view': view_set,
|
||||
},
|
||||
data = valid_data,
|
||||
partial = True,
|
||||
)
|
||||
|
||||
serializer.context['request'] = mock_request
|
||||
|
||||
if type(expected_result) is not bool:
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['status'][0] == expected_result
|
||||
|
||||
else:
|
||||
|
||||
assert serializer.is_valid(raise_exception = False) == expected_result
|
||||
|
||||
|
||||
|
||||
class TicketBaseSerializerInheritedCases(
|
||||
TicketBaseSerializerTestCases,
|
||||
):
|
||||
|
Reference in New Issue
Block a user