-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1313 from BLSQ/POLIO-1540-create-new-tab-sub-acti…
…vities-for-all-campaigns-polio-and-non-polio POLIO-1540 Create new tab sub activities for all campaigns polio and non polio
- Loading branch information
Showing
41 changed files
with
1,528 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# SubActivity and SubActivityScope Models and APIs | ||
|
||
## Models | ||
|
||
### SubActivity | ||
|
||
The `SubActivity` model represents a sub-activity within a round of a campaign. It has the following fields: | ||
|
||
- `round`: A foreign key to the `Round` model, representing the round to which the sub-activity belongs. | ||
- `name`: A string field representing the name of the sub-activity. | ||
- `age_unit`: A choice field representing the unit of age targeted by the sub-activity. The choices are "Months" and "Years". | ||
- `age_min`: An integer field representing the minimum age targeted by the sub-activity. | ||
- `age_max`: An integer field representing the maximum age targeted by the sub-activity. | ||
- `start_date`: A date field representing the start date of the sub-activity. | ||
- `end_date`: A date field representing the end date of the sub-activity. | ||
|
||
### SubActivityScope | ||
|
||
The `SubActivityScope` model represents the scope of a sub-activity, including the selection of an organizational unit and the vaccines used. It has the following fields: | ||
|
||
- `group`: A one-to-one field to the `Group` model, representing the group of organizational units for the sub-activity. | ||
- `subactivity`: A foreign key to the `SubActivity` model, representing the sub-activity to which the scope belongs. | ||
- `vaccine`: A choice field representing the vaccine used in the sub-activity. The choices are "mOPV2", "nOPV2", and "bOPV". | ||
|
||
## APIs | ||
|
||
The `SubActivity` API allows for the creation, retrieval, update, and deletion of sub-activities. The API endpoint is `/api/polio/campaigns_subactivities/`. | ||
|
||
### Create | ||
|
||
To create a new sub-activity, send a POST request to the endpoint with the following data: | ||
|
||
```json | ||
{ | ||
"round_number": <round_number>, | ||
"campaign": <campaign_obr_name>, | ||
"name": <subactivity_name>, | ||
"start_date": <start_date>, | ||
"end_date": <end_date>, | ||
"scopes": [ | ||
{ | ||
"group": { | ||
"name": <group_name>, | ||
"org_units": [<org_unit_id>] | ||
}, | ||
"vaccine": <vaccine_choice> | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Retrieve | ||
|
||
To retrieve all sub-activities, send a GET request to the endpoint. To retrieve a specific sub-activity, send a GET request to `/api/polio/campaigns_subactivities/<subactivity_id>/`. | ||
|
||
### Update | ||
|
||
To update a sub-activity, send a PUT request to `/api/polio/campaigns_subactivities/<subactivity_id>/` with the new data. | ||
|
||
### Delete | ||
|
||
To delete a sub-activity, send a DELETE request to `/api/polio/campaigns_subactivities/<subactivity_id>/`. | ||
|
||
## Permissions | ||
|
||
Only authenticated users can interact with the `SubActivity` API. The user must belong to the same account as the campaign associated with the round of the sub-activity. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
from django.shortcuts import get_object_or_404 | ||
from django_filters.rest_framework import DjangoFilterBackend # type: ignore | ||
from rest_framework import permissions, serializers | ||
|
||
from iaso.api.common import ModelViewSet | ||
from iaso.models import Group | ||
from plugins.polio.api.shared_serializers import GroupSerializer | ||
from plugins.polio.models import Round, SubActivity, SubActivityScope | ||
|
||
|
||
class SubActivityScopeSerializer(serializers.ModelSerializer): | ||
class Meta: | ||
model = SubActivityScope | ||
fields = ["group", "vaccine"] | ||
|
||
group = GroupSerializer(required=False) | ||
|
||
|
||
class SubActivityCreateUpdateSerializer(serializers.ModelSerializer): | ||
round_number = serializers.IntegerField(write_only=True, required=False) | ||
campaign = serializers.CharField(write_only=True, required=False) | ||
scopes = SubActivityScopeSerializer(many=True, required=False) | ||
|
||
class Meta: | ||
model = SubActivity | ||
fields = [ | ||
"id", | ||
"round_number", | ||
"campaign", | ||
"name", | ||
"start_date", | ||
"end_date", | ||
"scopes", | ||
"age_unit", | ||
"age_min", | ||
"age_max", | ||
] | ||
|
||
def create(self, validated_data): | ||
round_number = validated_data.pop("round_number", None) | ||
campaign = validated_data.pop("campaign", None) | ||
scopes_data = validated_data.pop("scopes", []) | ||
|
||
if round_number is not None and campaign is not None: | ||
the_round = get_object_or_404(Round, campaign__obr_name=campaign, number=round_number) | ||
validated_data["round"] = the_round | ||
|
||
if self.context["request"].user.iaso_profile.account != the_round.campaign.account: | ||
raise serializers.ValidationError( | ||
"You do not have permission to create a SubActivity for this Campaign." | ||
) | ||
|
||
else: | ||
raise serializers.ValidationError("Both round_number and campaign must be provided.") | ||
|
||
sub_activity = super().create(validated_data) | ||
|
||
for scope_data in scopes_data: | ||
group_data = scope_data.pop("group") | ||
group_data["source_version"] = self.context["request"].user.iaso_profile.account.default_version | ||
group_org_units = group_data.pop("org_units", []) | ||
group = Group.objects.create(**group_data) | ||
group.org_units.set(group_org_units) | ||
SubActivityScope.objects.create(subactivity=sub_activity, group=group, **scope_data) | ||
|
||
return sub_activity | ||
|
||
def update(self, instance, validated_data): | ||
scopes_data = validated_data.pop("scopes", None) | ||
|
||
if scopes_data is not None: | ||
# Get the groups associated with the current scopes | ||
groups_to_check = [scope.group for scope in instance.scopes.all()] | ||
|
||
# Delete the scopes | ||
instance.scopes.all().delete() | ||
|
||
# Check if the groups are used by any other SubActivityScope | ||
for group in groups_to_check: | ||
if not SubActivityScope.objects.filter(group=group).exists(): | ||
group.delete() | ||
|
||
for scope_data in scopes_data: | ||
group_data = scope_data.pop("group") | ||
group_data["source_version"] = self.context["request"].user.iaso_profile.account.default_version | ||
group_org_units = group_data.pop("org_units", []) | ||
group = Group.objects.create(**group_data) | ||
group.org_units.set(group_org_units) | ||
SubActivityScope.objects.create(subactivity=instance, group=group, **scope_data) | ||
|
||
return super().update(instance, validated_data) | ||
|
||
|
||
class SubActivityListDetailSerializer(serializers.ModelSerializer): | ||
round_id = serializers.IntegerField(source="round.id", read_only=True) | ||
scopes = SubActivityScopeSerializer(many=True) | ||
|
||
class Meta: | ||
model = SubActivity | ||
fields = ["id", "round_id", "name", "start_date", "end_date", "scopes", "age_unit", "age_min", "age_max"] | ||
|
||
|
||
class SubActivityViewSet(ModelViewSet): | ||
permission_classes = [permissions.IsAuthenticated] | ||
http_method_names = ["get", "head", "options", "post", "delete", "put"] | ||
model = SubActivity | ||
filter_backends = [DjangoFilterBackend] | ||
filterset_fields = {"round__campaign__obr_name": ["exact"], "round__id": ["exact"]} | ||
|
||
def get_serializer_class(self): | ||
if self.action in ["create", "update", "partial_update"]: | ||
return SubActivityCreateUpdateSerializer | ||
return SubActivityListDetailSerializer | ||
|
||
def get_queryset(self): | ||
return SubActivity.objects.filter(round__campaign__account=self.request.user.iaso_profile.account) | ||
|
||
def check_object_permissions(self, request, obj): | ||
super().check_object_permissions(request, obj) | ||
if request.user.iaso_profile.account != obj.round.campaign.account: | ||
self.permission_denied(request, message="Cannot access campaign") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.