diff --git a/api/flags/libraries/get_flag.py b/api/flags/libraries/get_flag.py index f02ea19ca8..15fe3dc279 100644 --- a/api/flags/libraries/get_flag.py +++ b/api/flags/libraries/get_flag.py @@ -1,7 +1,6 @@ from django.http import Http404 -from api.core.exceptions import NotFoundError -from api.flags.models import Flag, FlaggingRule +from api.flags.models import Flag def get_flag(pk): @@ -9,10 +8,3 @@ def get_flag(pk): return Flag.objects.get(pk=pk) except Flag.DoesNotExist: raise Http404 - - -def get_flagging_rule(pk): - try: - return FlaggingRule.objects.get(pk=pk) - except FlaggingRule.DoesNotExist: - raise NotFoundError({"flagging_rule": "Flagging rule not found - " + str(pk)}) diff --git a/api/flags/serializers.py b/api/flags/serializers.py index 3afd07a8d7..4285b23650 100644 --- a/api/flags/serializers.py +++ b/api/flags/serializers.py @@ -1,126 +1,34 @@ from rest_framework import serializers -from rest_framework.relations import PrimaryKeyRelatedField -from rest_framework.validators import UniqueValidator from api.core.serializers import PrimaryKeyRelatedSerializerField -from api.flags.enums import FlagLevels, FlagStatuses, FlagColours, FlagPermissions -from api.flags.models import Flag, FlaggingRule +from api.flags.enums import ( + FlagPermissions, + FlagStatuses, +) +from api.flags.models import Flag from api.teams.models import Team -from api.teams.serializers import TeamSerializer, TeamReadOnlySerializer -from lite_content.lite_api import strings - - -class FlagReadOnlySerializer(serializers.Serializer): - """ - More performant read_only flag serializer - """ - - id = serializers.UUIDField(read_only=True) - name = serializers.CharField(read_only=True) - alias = serializers.CharField(read_only=True) - colour = serializers.CharField(read_only=True) - level = serializers.CharField(read_only=True) - label = serializers.CharField(read_only=True) - status = serializers.CharField(read_only=True) - priority = serializers.IntegerField(read_only=True) - blocks_finalising = serializers.BooleanField(read_only=True) - removable_by = serializers.CharField(read_only=True) - team = PrimaryKeyRelatedSerializerField(queryset=Team.objects.all(), serializer=TeamReadOnlySerializer) - - -class FlaggingRuleReadOnlySerializer(serializers.Serializer): - level = serializers.CharField(read_only=True) - status = serializers.CharField(read_only=True) - matching_values = serializers.ListField() - matching_groups = serializers.ListField() - excluded_values = serializers.ListField() - - -class FlagwithFlaggingRulesReadOnlySerializer(FlagReadOnlySerializer): - flagging_rules = FlaggingRuleReadOnlySerializer(many=True, read_only=True) +from api.teams.serializers import TeamReadOnlySerializer class FlagSerializer(serializers.ModelSerializer): - name = serializers.CharField( - max_length=100, - validators=[UniqueValidator(queryset=Flag.objects.all(), lookup="iexact", message=strings.Flags.NON_UNIQUE)], - error_messages={"blank": strings.Flags.BLANK_NAME}, - ) - colour = serializers.ChoiceField(choices=FlagColours.choices, default=FlagColours.DEFAULT) - level = serializers.ChoiceField( - choices=FlagLevels.choices, - error_messages={"invalid_choice": "Select a parameter"}, - ) - label = serializers.CharField( - max_length=15, - required=False, - allow_blank=True, - error_messages={ - "blank": strings.Flags.ValidationErrors.LABEL_MISSING, - }, - ) - status = serializers.ChoiceField(choices=FlagStatuses.choices, default=FlagStatuses.ACTIVE) - priority = serializers.IntegerField( - default=0, - min_value=0, - max_value=100, - error_messages={ - "invalid": strings.Flags.ValidationErrors.PRIORITY, - "max_value": strings.Flags.ValidationErrors.PRIORITY_TOO_LARGE, - "min_value": strings.Flags.ValidationErrors.PRIORITY_NEGATIVE, - }, - ) - team = PrimaryKeyRelatedSerializerField(queryset=Team.objects.all(), serializer=TeamSerializer) - blocks_finalising = serializers.BooleanField( - required=True, - allow_null=False, - error_messages={ - "required": strings.Flags.ValidationErrors.BLOCKING_APPROVAL_MISSING, - }, - ) - removable_by = serializers.ChoiceField( - choices=FlagPermissions.choices, - default=FlagPermissions.DEFAULT, - allow_null=False, - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if self.context and not self.context.get("request").method == "GET": - self.initial_data["team"] = self.context.get("request").user.govuser.team_id - - if hasattr(self, "initial_data"): - if self.initial_data.get("colour") != FlagColours.DEFAULT: - self.fields["label"].required = True - self.fields["label"].allow_blank = False + team = PrimaryKeyRelatedSerializerField(queryset=Team.objects.all(), serializer=TeamReadOnlySerializer) class Meta: model = Flag fields = ( "id", "name", + "alias", + "colour", "level", - "team", - "status", "label", - "colour", + "status", "priority", "blocks_finalising", "removable_by", + "team", ) - def update(self, instance, validated_data): - instance.name = validated_data.get("name", instance.name) - instance.label = validated_data.get("label", instance.label) - instance.colour = validated_data.get("colour", instance.colour) - instance.priority = validated_data.get("priority", instance.priority) - instance.status = validated_data.get("status", instance.status) - instance.blocks_finalising = validated_data.get("blocks_finalising", instance.blocks_finalising) - instance.removable_by = validated_data.get("removable_by", instance.removable_by) - instance.save() - return instance - class FlagAssignmentSerializer(serializers.Serializer): flags = serializers.PrimaryKeyRelatedField(queryset=Flag.objects.all(), many=True) @@ -184,108 +92,3 @@ class CaseListFlagSerializer(serializers.Serializer): colour = serializers.CharField() priority = serializers.IntegerField() level = serializers.CharField() - - -class FlaggingRuleSerializer(serializers.ModelSerializer): - team = PrimaryKeyRelatedSerializerField(queryset=Team.objects.all(), serializer=TeamSerializer) - level = serializers.ChoiceField( - choices=FlagLevels.choices, - error_messages={ - "required": "Select a parameter", - "null": "Select a parameter", - }, - ) - status = serializers.ChoiceField(choices=FlagStatuses.choices, default=FlagStatuses.ACTIVE) - flag = PrimaryKeyRelatedField(queryset=Flag.objects.all(), error_messages={"null": strings.FlaggingRules.NO_FLAG}) - matching_values = serializers.ListField(child=serializers.CharField(), required=False) - matching_groups = serializers.ListField(child=serializers.CharField(), required=False) - excluded_values = serializers.ListField(child=serializers.CharField(), required=False) - is_for_verified_goods_only = serializers.BooleanField(required=False, allow_null=True) - - class Meta: - model = FlaggingRule - fields = ( - "id", - "team", - "level", - "flag", - "status", - "matching_values", - "matching_groups", - "excluded_values", - "is_for_verified_goods_only", - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if hasattr(self, "initial_data"): - if "level" not in self.initial_data: - self.initial_data["level"] = self.instance.level if self.instance else None - if "matching_values" not in self.initial_data: - self.initial_data["matching_values"] = self.instance.matching_values if self.instance else [] - if "matching_groups" not in self.initial_data: - self.initial_data["matching_groups"] = self.instance.matching_groups if self.instance else [] - if "excluded_values" not in self.initial_data: - self.initial_data["excluded_values"] = self.instance.excluded_values if self.instance else [] - if "is_for_verified_goods_only" not in self.initial_data: - self.initial_data["is_for_verified_goods_only"] = ( - self.instance.is_for_verified_goods_only if self.instance else None - ) - - def update(self, instance, validated_data): - instance.status = validated_data.get("status", instance.status) - instance.matching_values = validated_data.get("matching_values", instance.matching_values) - instance.matching_groups = validated_data.get("matching_groups", instance.matching_groups) - instance.excluded_values = validated_data.get("excluded_values", instance.excluded_values) - instance.flag = validated_data.get("flag", instance.flag) - instance.is_for_verified_goods_only = validated_data.get( - "is_for_verified_goods_only", instance.is_for_verified_goods_only - ) - instance.save() - return instance - - def validate(self, data): - errors = {} - validated_data = super().validate(data) - - matching_values = validated_data.get("matching_values") - matching_groups = validated_data.get("matching_groups") - excluded_values = validated_data.get("excluded_values") - - if validated_data["level"] == FlagLevels.GOOD: - if not matching_values and not matching_groups and not excluded_values: - errors["matching_values"] = "Enter a control list entry" - errors["matching_groups"] = "Enter a control list entry" - errors["excluded_values"] = "Enter a control list entry" - elif validated_data["level"] == FlagLevels.DESTINATION: - if not matching_values: - errors["matching_values"] = "Enter a destination" - elif validated_data["level"] == FlagLevels.CASE: - if not matching_values: - errors["matching_values"] = "Enter an application type" - - if ( - "level" in validated_data - and validated_data["level"] == FlagLevels.GOOD - and validated_data["is_for_verified_goods_only"] is None - ): - errors["is_for_verified_goods_only"] = strings.FlaggingRules.NO_ANSWER_VERIFIED_ONLY - - if errors: - raise serializers.ValidationError(errors) - - return validated_data - - -class FlaggingRuleListSerializer(serializers.Serializer): - id = serializers.UUIDField() - team = TeamReadOnlySerializer() - level = serializers.ChoiceField(choices=FlagLevels.choices) - status = serializers.ChoiceField(choices=FlagStatuses.choices) - flag = PrimaryKeyRelatedField(queryset=Flag.objects.all()) - flag_name = serializers.CharField(source="flag.name") - matching_values = serializers.ListField(child=serializers.CharField()) - matching_groups = serializers.ListField(child=serializers.CharField()) - excluded_values = serializers.ListField(child=serializers.CharField()) - is_for_verified_goods_only = serializers.BooleanField() diff --git a/api/flags/tests/test_create_flags.py b/api/flags/tests/test_create_flags.py deleted file mode 100644 index d496112cc9..0000000000 --- a/api/flags/tests/test_create_flags.py +++ /dev/null @@ -1,93 +0,0 @@ -from django.urls import reverse -from parameterized import parameterized -from rest_framework import status - -from api.flags.enums import FlagLevels, FlagColours -from lite_content.lite_api import strings -from test_helpers.clients import DataTestClient - - -class FlagsCreateTest(DataTestClient): - - url = reverse("flags:flags") - - def test_gov_user_can_create_flags(self): - data = { - "name": "new flag", - "level": "Organisation", - "colour": FlagColours.ORANGE, - "label": "This is label", - "blocks_finalising": False, - } - - response = self.client.post(self.url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response_data["name"], "new flag") - self.assertEqual(response_data["level"], "Organisation") - self.assertEqual(response_data["colour"], FlagColours.ORANGE) - self.assertEqual(response_data["label"], "This is label") - self.assertEqual( - response_data["team"], - { - "id": str(self.team.id), - "name": self.team.name, - "part_of_ecju": False, - "department": None, - "is_ogd": False, - "alias": None, - }, - ) - - @parameterized.expand( - [ - [""], # Blank - ["test"], # Case insensitive duplicate names - [" TesT "], - ["TEST"], - ["a" * 21], # Too long a name - ] - ) - def test_create_flag_failure(self, name): - self.create_flag("test", FlagLevels.CASE, self.team) - - response = self.client.post(self.url, {"name": name}, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_cannot_set_priority_to_less_than_0(self): - data = {"name": "new flag", "level": "Organisation", "priority": -1} - - response = self.client.post(self.url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn(strings.Flags.ValidationErrors.PRIORITY_NEGATIVE, response_data["errors"]["priority"]) - - def test_cannot_set_priority_to_greater_than_100(self): - data = {"name": "new flag", "level": "Organisation", "priority": 101} - - response = self.client.post(self.url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn(strings.Flags.ValidationErrors.PRIORITY_TOO_LARGE, response_data["errors"]["priority"]) - - def test_cannot_create_flag_with_colour_and_no_label(self): - data = {"name": "new flag", "level": "Organisation", "colour": FlagColours.ORANGE, "label": ""} - - response = self.client.post(self.url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn(strings.Flags.ValidationErrors.LABEL_MISSING, response.json()["errors"]["label"]) - - def test_cannot_create_flag_without_blocks_finalising(self): - data = {"name": "new flag", "level": "Organisation", "colour": FlagColours.ORANGE, "label": "This is label"} - - response = self.client.post(self.url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual( - response.json()["errors"]["blocks_finalising"], [strings.Flags.ValidationErrors.BLOCKING_APPROVAL_MISSING] - ) diff --git a/api/flags/tests/test_endpoints_response_flags.py b/api/flags/tests/test_endpoints_response_flags.py index 84a138fc49..4b1b282fcf 100644 --- a/api/flags/tests/test_endpoints_response_flags.py +++ b/api/flags/tests/test_endpoints_response_flags.py @@ -9,9 +9,3 @@ def test_flags_list(self): def test_flags_detail(self): self.call_endpoint(self.get_gov_headers(), self.url + self.get_flag_id()) - - def test_flagging_rules_list(self): - self.call_endpoint(self.get_gov_headers(), self.url + "rules/") - - def test_flagging_rules_detail(self): - self.call_endpoint(self.get_gov_headers(), self.url + "rules/" + self.get_flagging_rules_id()) diff --git a/api/flags/tests/test_list_flagging_rules.py b/api/flags/tests/test_list_flagging_rules.py deleted file mode 100644 index 464ef153b9..0000000000 --- a/api/flags/tests/test_list_flagging_rules.py +++ /dev/null @@ -1,98 +0,0 @@ -from django.urls import reverse -from rest_framework import status - -from api.flags.enums import FlagStatuses -from test_helpers.clients import DataTestClient - - -class FlaggingRulesListTests(DataTestClient): - url = reverse("flags:flagging_rules") - - def test_gov_user_can_see_all_flags(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - - response = self.client.get(self.url, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_gov_user_cannot_see_flagging_rules_without_permission(self): - response = self.client.get(self.url, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_gov_user_can_see_only_filtered_case_level_flagging_rules(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - other_team = self.create_team("Team") - - flag1 = self.create_flag("Flag1", "Case", self.team) - country_level_flag = self.create_flag("Flag2", "Organisation", self.team) - other_team_flag = self.create_flag("Flag3", "Case", other_team) - good_level_flag = self.create_flag("Flag4", "Case", self.team) - - flag1_rule = self.create_flagging_rule(flag=flag1, level="Case", team=self.team, matching_values=["SIEL"]) - country_level_flag_rule = self.create_flagging_rule( - flag=country_level_flag, level="Destination", team=self.team, matching_values=["FR"] - ) - other_team_flag_rule = self.create_flagging_rule( - flag=other_team_flag, level="Case", team=other_team, matching_values=["OIEL"] - ) - good_level_flag_rule = self.create_flagging_rule( - flag=good_level_flag, level="Good", team=self.team, matching_values=["ML2a"] - ) - - url = f"{self.url}?level=Case" - response = self.client.get(url, **self.gov_headers) - - response_data = response.json() - self.assertEqual(response.status_code, status.HTTP_200_OK) - returned_rules = [flagging_rule["id"] for flagging_rule in response_data["results"]] - self.assertIn(str(flag1_rule.id), returned_rules) - self.assertNotIn(str(country_level_flag_rule.id), returned_rules) - self.assertIn(str(other_team_flag_rule.id), returned_rules) - self.assertNotIn(str(good_level_flag_rule.id), returned_rules) - - def test_gov_user_can_filter_by_only_show_my_team(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - other_team = self.create_team("Team") - - country_level_flag = self.create_flag("Flag2", "Organisation", self.team) - other_team_flag = self.create_flag("Flag3", "Case", other_team) - country_level_flag_rule = self.create_flagging_rule( - flag=country_level_flag, level="Destination", team=self.team, matching_values=["FR"] - ) - other_team_flag_rule = self.create_flagging_rule( - flag=other_team_flag, level="Case", team=other_team, matching_values=["OIEL"] - ) - - url = f"{self.url}?only_my_team=True" - - response = self.client.get(url, **self.gov_headers) - response_data = response.json() - self.assertEqual(response.status_code, status.HTTP_200_OK) - returned_rules = [flagging_rule["id"] for flagging_rule in response_data["results"]] - - self.assertIn(str(country_level_flag_rule.id), returned_rules) - self.assertNotIn(str(other_team_flag_rule.id), returned_rules) - - def test_gov_user_can_filter_by_active_flags(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - flag1 = self.create_flag("Flag1", "Case", self.team) - - flag1_rule_1 = self.create_flagging_rule(flag=flag1, level="Case", team=self.team, matching_values=["SIEL"]) - flag1_rule_2 = self.create_flagging_rule( - flag=flag1, level="Case", team=self.team, matching_values=["OIEL"], status=FlagStatuses.DEACTIVATED - ) - - url = f"{self.url}" - - response = self.client.get(url, **self.gov_headers) - response_data = response.json() - self.assertEqual(response.status_code, status.HTTP_200_OK) - returned_rules = [flagging_rule["id"] for flagging_rule in response_data["results"]] - - self.assertIn(str(flag1_rule_1.id), returned_rules) - self.assertNotIn(str(flag1_rule_2.id), returned_rules) diff --git a/api/flags/tests/test_update_flagging_rules.py b/api/flags/tests/test_update_flagging_rules.py deleted file mode 100644 index a3edb325a7..0000000000 --- a/api/flags/tests/test_update_flagging_rules.py +++ /dev/null @@ -1,112 +0,0 @@ -from django.urls import reverse -from rest_framework import status - -from api.flags.enums import FlagStatuses, FlagLevels -from api.flags.tests.factories import FlagFactory -from test_helpers.clients import DataTestClient - - -class FlaggingRulesUpdateTest(DataTestClient): - def test_flagging_rule_can_be_deactivated(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - - flag = self.create_flag("New Flag", "Case", self.team) - flagging_rule = self.create_flagging_rule(level="Case", flag=flag, team=self.team, matching_values=["SIEL"]) - - data = { - "status": FlagStatuses.DEACTIVATED, - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - response = self.client.put(url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response_data["flagging_rule"]["status"], FlagStatuses.DEACTIVATED) - - def test_flagging_rule_cannot_be_deactivated_by_a_user_outside_flags_team(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - team = self.create_team("Secondary team") - flag = self.create_flag("New Flag", "Case", team) - flagging_rule = self.create_flagging_rule(level="Case", flag=flag, team=team, matching_values=["SIEL"]) - - data = { - "status": FlagStatuses.DEACTIVATED, - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - response = self.client.put(url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertEqual(flag.status, FlagStatuses.ACTIVE) - - def test_flagging_rule_level_cannot_be_changed(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - flag = self.create_flag("New Flag", "Case", self.team) - flagging_rule = self.create_flagging_rule(level="Case", flag=flag, team=self.team, matching_values=["SIEL"]) - - data = { - "level": "Good", - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - self.client.put(url, data, **self.gov_headers) - - self.assertEqual(flagging_rule.level, "Case") - - def test_flagging_rule_can_change_flag(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - flag = self.create_flag("New Flag", "Case", self.team) - flag_2 = self.create_flag("other flag", "Case", self.team) - flagging_rule = self.create_flagging_rule(level="Case", flag=flag, team=self.team, matching_values=["SIEL"]) - - data = { - "flag": str(flag_2.id), - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - self.client.put(url, data, **self.gov_headers) - - flagging_rule.refresh_from_db() - - self.assertEqual(flagging_rule.flag, flag_2) - - def test_flagging_rule_can_change_matching_values(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - flag = self.create_flag("New Flag", "Case", self.team) - flagging_rule = self.create_flagging_rule(level="Case", flag=flag, team=self.team, matching_values=["SIEL"]) - - data = { - "matching_values": ["OIEL"], - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - self.client.put(url, data, **self.gov_headers) - - flagging_rule.refresh_from_db() - - self.assertEqual(flagging_rule.matching_values, ["OIEL"]) - - def test_flagging_rule_can_change_verified_answer(self): - self.gov_user.role = self.super_user_role - self.gov_user.save() - flag = FlagFactory(level=FlagLevels.GOOD, team=self.team) - flagging_rule = self.create_flagging_rule( - level="Good", flag=flag, team=self.team, matching_values=["ML1"], is_for_verified_goods_only="False" - ) - - data = { - "is_for_verified_goods_only": "True", - } - - url = reverse("flags:flagging_rule", kwargs={"pk": flagging_rule.id}) - self.client.put(url, data, **self.gov_headers) - - flagging_rule.refresh_from_db() - - self.assertTrue(flagging_rule.is_for_verified_goods_only) diff --git a/api/flags/tests/test_update_flags.py b/api/flags/tests/test_update_flags.py deleted file mode 100644 index 2b4a7354f5..0000000000 --- a/api/flags/tests/test_update_flags.py +++ /dev/null @@ -1,104 +0,0 @@ -from django.urls import reverse -from rest_framework import status - -from api.core.constants import GovPermissions -from api.flags.enums import FlagStatuses, FlagColours, FlagLevels -from api.flags.tests.factories import FlagFactory -from lite_content.lite_api import strings -from test_helpers.clients import DataTestClient - - -class FlagsUpdateTest(DataTestClient): - def test_flag_can_be_deactivated(self): - self.gov_user.role.permissions.set([GovPermissions.ACTIVATE_FLAGS.name]) - flag = FlagFactory(team=self.team) - - data = { - "status": FlagStatuses.DEACTIVATED, - } - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.patch(url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response_data["status"], FlagStatuses.DEACTIVATED) - - def test_flag_cannot_be_deactivated_without_permission(self): - flag = FlagFactory(team=self.team) - data = { - "status": FlagStatuses.DEACTIVATED, - } - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.patch(url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_flag_cannot_be_deactivated_by_a_user_outside_flags_team(self): - team = self.create_team("Secondary team") - flag = FlagFactory(team=team) - - data = { - "status": FlagStatuses.DEACTIVATED, - } - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.put(url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - self.assertEqual(flag.status, FlagStatuses.ACTIVE) - - def test_flag_level_cannot_be_changed(self): - team = self.create_team("Secondary team") - flag = FlagFactory(team=team, level=FlagLevels.CASE) - - data = { - "level": "Good", - } - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - self.client.put(url, data, **self.gov_headers) - - self.assertEqual(flag.level, "Case") - - def test_colour_can_be_changed_from_default(self): - flag = FlagFactory(team=self.team) - label_text = "This a label" - - data = {"colour": FlagColours.ORANGE, "label": label_text} - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.patch(url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response_data["colour"], FlagColours.ORANGE) - self.assertEqual(response_data["label"], label_text) - - def test_colour_cannot_be_changed_from_default_without_adding_a_label(self): - flag = FlagFactory(team=self.team) - - data = {"colour": FlagColours.ORANGE, "label": ""} - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.patch(url, data, **self.gov_headers) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertIn(strings.Flags.ValidationErrors.LABEL_MISSING, response.json()["errors"]["label"]) - - flag.refresh_from_db() - self.assertEqual(flag.colour, FlagColours.DEFAULT) - self.assertEqual(flag.label, None) - - def test_priority_can_be_updated(self): - flag = FlagFactory(team=self.team) - - data = {"priority": 1} - - url = reverse("flags:flag", kwargs={"pk": flag.id}) - response = self.client.patch(url, data, **self.gov_headers) - response_data = response.json() - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response_data["priority"], 1) diff --git a/api/flags/urls.py b/api/flags/urls.py index fdf16dcfca..93e0bbc70d 100644 --- a/api/flags/urls.py +++ b/api/flags/urls.py @@ -5,9 +5,7 @@ app_name = "flags" urlpatterns = [ - path("", views.FlagsListCreateView.as_view(), name="flags"), - path("/", views.FlagsRetrieveUpdateView.as_view(), name="flag"), + path("", views.FlagsListView.as_view(), name="flags"), + path("/", views.FlagsRetrieveView.as_view(), name="flag"), path("assign/", views.AssignFlags.as_view(), name="assign_flags"), - path("rules/", views.FlaggingRules.as_view(), name="flagging_rules"), - path("rules//", views.FlaggingRuleDetail.as_view(), name="flagging_rule"), ] diff --git a/api/flags/views.py b/api/flags/views.py index 590fcf9e37..555322cc17 100644 --- a/api/flags/views.py +++ b/api/flags/views.py @@ -1,9 +1,11 @@ -from django.db import transaction from django.db.models import Q from django.http import JsonResponse from rest_framework import status -from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView +from rest_framework.generics import ( + ListAPIView, + RetrieveAPIView, +) from rest_framework.parsers import JSONParser from rest_framework.views import APIView @@ -17,21 +19,14 @@ from api.cases.models import Case from api.core.authentication import GovAuthentication -from api.core.constants import GovPermissions from api.core.helpers import str_to_bool -from api.core.permissions import assert_user_has_permission from api.flags.enums import FlagLevels, FlagStatuses, SystemFlags from api.flags.helpers import get_object_of_level -from api.flags.libraries.get_flag import get_flagging_rule -from api.flags.models import Flag, FlaggingRule +from api.flags.models import Flag from api.flags.serializers import ( FlagSerializer, FlagAssignmentSerializer, - FlaggingRuleSerializer, - FlagReadOnlySerializer, - FlaggingRuleListSerializer, - FlagwithFlaggingRulesReadOnlySerializer, ) from api.goods.models import Good @@ -43,24 +38,10 @@ from api.queries.end_user_advisories.models import EndUserAdvisoryQuery from api.queries.goods_query.models import GoodsQuery -from lite_routing.routing_rules_internal.flagging_engine import ( - apply_flagging_rule_to_all_open_cases, - apply_flagging_rule_for_flag, -) - -from lite_content.lite_api import strings - -class FlagsListCreateView(ListCreateAPIView): +class FlagsListView(ListAPIView): authentication_classes = (GovAuthentication,) - - def get_serializer_class(self): - if self.request.method == "GET": - if self.request.GET.get("include_flagging_rules"): - return FlagwithFlaggingRulesReadOnlySerializer - return FlagReadOnlySerializer - else: - return FlagSerializer + serializer_class = FlagSerializer def get_queryset(self): case = self.request.GET.get("case") @@ -102,20 +83,13 @@ def get_queryset(self): return flags.order_by("name").select_related("team") -class FlagsRetrieveUpdateView(RetrieveUpdateAPIView): +class FlagsRetrieveView(RetrieveAPIView): authentication_classes = (GovAuthentication,) serializer_class = FlagSerializer def get_queryset(self): return Flag.objects.filter(team=self.request.user.govuser.team).exclude(level=FlagLevels.PARTY_ON_APPLICATION) - def perform_update(self, serializer): - # if status is being updated, ensure user has permission - if self.request.data.get("status"): - assert_user_has_permission(self.request.user.govuser, GovPermissions.ACTIVATE_FLAGS) - serializer.save() - apply_flagging_rule_for_flag(self.kwargs["pk"]) - class AssignFlags(APIView): authentication_classes = (GovAuthentication,) @@ -303,72 +277,3 @@ def _get_case_for_destination(party): if qs.exists(): return qs.first().get_case() - - -class FlaggingRules(ListCreateAPIView): - authentication_classes = (GovAuthentication,) - - def get_serializer_class(self): - if self.request.method == "GET": - return FlaggingRuleListSerializer - else: - return FlaggingRuleSerializer - - def get_queryset(self): - assert_user_has_permission(self.request.user.govuser, GovPermissions.MANAGE_FLAGGING_RULES) - rules = FlaggingRule.objects.all().prefetch_related("flag", "team") - - include_deactivated = self.request.query_params.get("include_deactivated", "") - if not include_deactivated: - rules = rules.filter(status=FlagStatuses.ACTIVE) - - level = self.request.query_params.get("level", "") - if level: - rules = rules.filter(level=level) - - only_my_team = self.request.query_params.get("only_my_team", "") - if only_my_team: - rules = rules.filter(team=self.request.user.govuser.team) - - return rules - - @transaction.atomic - def post(self, request): - assert_user_has_permission(self.request.user.govuser, GovPermissions.MANAGE_FLAGGING_RULES) - json = request.data - json["team"] = self.request.user.govuser.team.id - - serializer = FlaggingRuleSerializer(data=request.data) - - if serializer.is_valid(): - flagging_rule = serializer.save() - apply_flagging_rule_to_all_open_cases(flagging_rule) - return JsonResponse(data=serializer.data, status=status.HTTP_201_CREATED) - - return JsonResponse(data={"errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST) - - -class FlaggingRuleDetail(APIView): - authentication_classes = (GovAuthentication,) - - def get(self, request, pk): - assert_user_has_permission(self.request.user.govuser, GovPermissions.MANAGE_FLAGGING_RULES) - flagging_rule = get_flagging_rule(pk) - serializer = FlaggingRuleSerializer(flagging_rule) - return JsonResponse(data={"flag": serializer.data}) - - def put(self, request, pk): - assert_user_has_permission(self.request.user.govuser, GovPermissions.MANAGE_FLAGGING_RULES) - flagging_rule = get_flagging_rule(pk) - - if request.user.govuser.team != flagging_rule.team: - return JsonResponse(data={"errors": strings.Flags.FORBIDDEN}, status=status.HTTP_403_FORBIDDEN) - - serializer = FlaggingRuleSerializer(instance=flagging_rule, data=request.data, partial=True) - - if serializer.is_valid(): - flagging_rule = serializer.save() - apply_flagging_rule_to_all_open_cases(flagging_rule) - return JsonResponse(data={"flagging_rule": serializer.data}) - - return JsonResponse(data={"errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST) diff --git a/lite_routing b/lite_routing index 7baa85e928..0c6c13cd0b 160000 --- a/lite_routing +++ b/lite_routing @@ -1 +1 @@ -Subproject commit 7baa85e9280177c295c64cde72be1aba7ca8e48f +Subproject commit 0c6c13cd0b7cd5a6e942b08a013c4613f823bc3f