From 81fe921afc94444c9bd612c86ac2293ee2503201 Mon Sep 17 00:00:00 2001 From: Priya Thakur Date: Wed, 7 Feb 2024 14:58:31 +0800 Subject: [PATCH 1/3] add partially threats tab to OccurrenceReport form (need more clarification) --- boranga/components/occurrence/api.py | 132 +++++- boranga/components/occurrence/models.py | 60 +++ boranga/components/occurrence/serializers.py | 72 +++ .../components/species_and_communities/api.py | 97 +++-- boranga/frontend/boranga/src/api.js | 1 + .../common/occurrence/ocr_threats.vue | 412 ++++++++++++++++++ .../common/species_communities/add_threat.vue | 17 +- .../src/components/form_occurrence_report.vue | 29 +- .../migrations/0190_ocrconservationthreat.py | 30 ++ .../includes/primary_menu.html | 2 +- boranga/urls.py | 1 + 11 files changed, 783 insertions(+), 70 deletions(-) create mode 100644 boranga/frontend/boranga/src/components/common/occurrence/ocr_threats.vue create mode 100644 boranga/migrations/0190_ocrconservationthreat.py diff --git a/boranga/components/occurrence/api.py b/boranga/components/occurrence/api.py index d54dbd5e..bea55ad7 100644 --- a/boranga/components/occurrence/api.py +++ b/boranga/components/occurrence/api.py @@ -76,6 +76,8 @@ Location, ObserverDetail, OccurrenceReportDocument, + OCRConservationThreat, + OccurrenceReportUserAction, ) from boranga.components.occurrence.serializers import( ListOccurrenceReportSerializer, @@ -97,6 +99,8 @@ OccurrenceReportLogEntrySerializer, OccurrenceReportDocumentSerializer, SaveOccurrenceReportDocumentSerializer, + OCRConservationThreatSerializer, + SaveOCRConservationThreatSerializer, ) from boranga.components.occurrence.utils import ( @@ -1038,6 +1042,24 @@ def documents(self, request, *args, **kwargs): except Exception as e: print(traceback.print_exc()) raise serializers.ValidationError(str(e)) + + @detail_route(methods=['GET',], detail=True) + def threats(self, request, *args, **kwargs): + try: + instance = self.get_object() + qs = instance.ocr_threats.all() + qs = qs.order_by('-date_observed') + serializer = OCRConservationThreatSerializer(qs,many=True, context={'request':request}) + return Response(serializer.data) + except serializers.ValidationError: + print(traceback.print_exc()) + raise + except ValidationError as e: + print(traceback.print_exc()) + raise serializers.ValidationError(repr(e.error_dict)) + except Exception as e: + print(traceback.print_exc()) + raise serializers.ValidationError(str(e)) class ObserverDetailViewSet(viewsets.ModelViewSet): @@ -1119,32 +1141,118 @@ def reinstate(self, request, *args, **kwargs): raise serializers.ValidationError(str(e)) def update(self, request, *args, **kwargs): + try: + with transaction.atomic(): + instance = self.get_object() + serializer = SaveOccurrenceReportDocumentSerializer(instance, data=json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception=True) + serializer.save() + instance.add_documents(request) + instance.uploaded_by = request.user.id + instance.save() + return Response(serializer.data) + except Exception as e: + print(traceback.print_exc()) + raise serializers.ValidationError(str(e)) + + + def create(self, request, *args, **kwargs): + try: + with transaction.atomic(): + serializer = SaveOccurrenceReportDocumentSerializer(data= json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception = True) + instance = serializer.save() + instance.add_documents(request) + instance.uploaded_by = request.user.id + instance.save() + return Response(serializer.data) + except serializers.ValidationError: + print(traceback.print_exc()) + raise + except ValidationError as e: + if hasattr(e,'error_dict'): + raise serializers.ValidationError(repr(e.error_dict)) + else: + if hasattr(e,'message'): + raise serializers.ValidationError(e.message) + except Exception as e: + print(traceback.print_exc()) + raise serializers.ValidationError(str(e)) + + +class OCRConservationThreatViewSet(viewsets.ModelViewSet): + queryset = OCRConservationThreat.objects.all().order_by('id') + serializer_class = OCRConservationThreatSerializer + + @detail_route(methods=['GET',], detail=True) + def discard(self, request, *args, **kwargs): try: instance = self.get_object() - serializer = SaveOccurrenceReportDocumentSerializer(instance, data=json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception=True) - serializer.save() - instance.add_documents(request) - instance.uploaded_by = request.user.id + instance.visible = False instance.save() + if instance.occurrence_report: + instance.occurrence_report.log_user_action(OccurrenceReportUserAction.ACTION_DISCARD_THREAT.format(instance.threat_number,instance.occurrence_report.occurrence_report_number),request) + serializer = self.get_serializer(instance) return Response(serializer.data) + except serializers.ValidationError: + print(traceback.print_exc()) + raise + except ValidationError as e: + print(traceback.print_exc()) + raise serializers.ValidationError(repr(e.error_dict)) except Exception as e: print(traceback.print_exc()) raise serializers.ValidationError(str(e)) - - def create(self, request, *args, **kwargs): + @detail_route(methods=['GET',], detail=True) + def reinstate(self, request, *args, **kwargs): try: - serializer = SaveOccurrenceReportDocumentSerializer(data= json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception = True) - instance = serializer.save() - instance.add_documents(request) - instance.uploaded_by = request.user.id + instance = self.get_object() + instance.visible = True instance.save() + if instance.occurrence_report: + instance.occurrence_report.log_user_action(OccurrenceReportUserAction.ACTION_REINSTATE_THREAT.format(instance.threat_number,instance.occurrence_report.occurrence_report_number),request) + serializer = self.get_serializer(instance) return Response(serializer.data) except serializers.ValidationError: print(traceback.print_exc()) raise + except ValidationError as e: + print(traceback.print_exc()) + raise serializers.ValidationError(repr(e.error_dict)) + except Exception as e: + print(traceback.print_exc()) + raise serializers.ValidationError(str(e)) + + def update(self, request, *args, **kwargs): + try: + with transaction.atomic(): + instance = self.get_object() + serializer = SaveOCRConservationThreatSerializer(instance, data=json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception=True) + serializer.save() + if instance.occurrence_report: + instance.occurrence_report.log_user_action(OccurrenceReportUserAction.ACTION_UPDATE_THREAT.format(instance.threat_number,instance.occurrence_report.occurrence_report_number),request) + serializer = self.get_serializer(instance) + return Response(serializer.data) + except Exception as e: + print(traceback.print_exc()) + raise serializers.ValidationError(str(e)) + + + def create(self, request, *args, **kwargs): + try: + with transaction.atomic(): + serializer = SaveOCRConservationThreatSerializer(data= json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception = True) + instance = serializer.save() + if instance.occurrence_report: + instance.occurrence_report.log_user_action(OccurrenceReportUserAction.ACTION_ADD_THREAT.format(instance.threat_number,instance.occurrence_report.occurrence_report_number),request) + serializer = self.get_serializer(instance) + return Response(serializer.data) + except serializers.ValidationError: + print(traceback.print_exc()) + raise except ValidationError as e: if hasattr(e,'error_dict'): raise serializers.ValidationError(repr(e.error_dict)) diff --git a/boranga/components/occurrence/models.py b/boranga/components/occurrence/models.py index cd3c9e9f..08d49a03 100644 --- a/boranga/components/occurrence/models.py +++ b/boranga/components/occurrence/models.py @@ -38,6 +38,11 @@ GroupType, Species, Community, + ThreatCategory, + ThreatAgent, + PotentialImpact, + PotentialThreatOnset, + CurrentImpact, ) from boranga.components.conservation_status.models import ConservationStatus from boranga.ordered_model import OrderedModel @@ -423,6 +428,18 @@ class OccurrenceReportUserAction(UserAction): COMMENT_REFERRAL = "Referral {} for occurrence report proposal {} has been commented by {}" CONCLUDE_REFERRAL = "Referral {} for occurrence report proposal {} has been concluded by {}" + # Document + ACTION_ADD_DOCUMENT= "Document {} added for occurrence report {}" + ACTION_UPDATE_DOCUMENT= "Document {} updated for occurrence report {}" + ACTION_DISCARD_DOCUMENT= "Document {} discarded for occurrence report {}" + ACTION_REINSTATE_DOCUMENT= "Document {} reinstated for occurrence report {}" + + # Threat + ACTION_ADD_THREAT= "Threat {} added for occurrence report {}" + ACTION_UPDATE_THREAT= "Threat {} updated for occurrence report {}" + ACTION_DISCARD_THREAT= "Threat {} discarded for occurrence report {}" + ACTION_REINSTATE_THREAT= "Threat {} reinstated for occurrence report {}" + class Meta: app_label = 'boranga' @@ -1280,3 +1297,46 @@ def add_documents(self, request): except: raise return + +class OCRConservationThreat(models.Model): + """ + Threat for a occurrence_report in a particular location. + + NB: Maybe make many to many + + Has a: + - occurrence_report + Used for: + - OccurrenceReport + Is: + - Table + """ + occurrence_report = models.ForeignKey(OccurrenceReport, on_delete=models.CASCADE, null=True, blank=True , related_name="ocr_threats") + threat_number = models.CharField(max_length=9, blank=True, default='') + threat_category = models.ForeignKey(ThreatCategory, on_delete=models.CASCADE, default=None, null=True, blank=True) + threat_agent = models.ForeignKey(ThreatAgent, on_delete=models.SET_NULL, default=None, null=True, blank=True) + current_impact = models.ForeignKey(CurrentImpact, on_delete=models.SET_NULL, default=None, null=True, blank=True) + potential_impact = models.ForeignKey(PotentialImpact, on_delete=models.SET_NULL, default=None, null=True, blank=True) + potential_threat_onset = models.ForeignKey(PotentialThreatOnset, on_delete=models.SET_NULL, default=None, null=True, blank=True) + comment = models.CharField(max_length=512, + default="None") + date_observed = models.DateField(blank =True, null=True) + visible = models.BooleanField(default=True) # to prevent deletion, hidden and still be available in history + + + class Meta: + app_label = 'boranga' + + def __str__(self): + return str(self.id) # TODO: is the most appropriate? + + def save(self, *args, **kwargs): + super(OCRConservationThreat, self).save(*args,**kwargs) + if self.threat_number == '': + new_threat_id = 'T{}'.format(str(self.pk)) + self.threat_number = new_threat_id + self.save() + + @property + def source(self): + return self.occurrence_report.id diff --git a/boranga/components/occurrence/serializers.py b/boranga/components/occurrence/serializers.py index d4383e6d..11acd886 100644 --- a/boranga/components/occurrence/serializers.py +++ b/boranga/components/occurrence/serializers.py @@ -29,6 +29,7 @@ OccurrenceReportLogEntry, OccurrenceReportUserAction, OccurrenceReportDocument, + OCRConservationThreat, ) from boranga.components.users.serializers import UserSerializer @@ -941,3 +942,74 @@ class Meta: 'document_sub_category', ) + +class OCRConservationThreatSerializer(serializers.ModelSerializer): + threat_category = serializers.SerializerMethodField() + threat_agent = serializers.SerializerMethodField() + current_impact_name = serializers.SerializerMethodField() + potential_impact_name = serializers.SerializerMethodField() + potential_threat_onset_name = serializers.SerializerMethodField() + class Meta: + model = OCRConservationThreat + fields = ( + 'id', + 'threat_number', + 'threat_category_id', + 'threat_category', + 'threat_agent', + 'threat_agent_id', + 'current_impact', + 'current_impact_name', + 'potential_impact', + 'potential_impact_name', + 'potential_threat_onset', + 'potential_threat_onset_name', + 'comment', + 'date_observed', + 'source', + 'occurrence_report', + 'visible', + ) + read_only_fields = ('id','threat_number',) + + def get_threat_category(self,obj): + if obj.threat_category: + return obj.threat_category.name + + def get_threat_agent(self,obj): + if obj.threat_agent: + return obj.threat_agent.name + + def get_current_impact_name(self,obj): + if obj.current_impact: + return obj.current_impact.name + + def get_potential_impact_name(self,obj): + if obj.potential_impact: + return obj.potential_impact.name + + def get_potential_threat_onset_name(self,obj): + if obj.potential_threat_onset: + return obj.potential_threat_onset.name + + +class SaveOCRConservationThreatSerializer(serializers.ModelSerializer): + + threat_category_id = serializers.IntegerField(required=False, allow_null=True, write_only= True) + threat_agent_id = serializers.IntegerField(required=False, allow_null=True, write_only= True) + date_observed = serializers.DateField(format='%Y-%m-%d', required=False, allow_null = True) + + class Meta: + model = OCRConservationThreat + fields = ( + 'id', + 'occurrence_report', + 'threat_category_id', + 'threat_agent_id', + 'comment', + 'current_impact', + 'potential_impact', + 'potential_threat_onset', + 'date_observed', + ) + diff --git a/boranga/components/species_and_communities/api.py b/boranga/components/species_and_communities/api.py index fdf90248..f984c50f 100755 --- a/boranga/components/species_and_communities/api.py +++ b/boranga/components/species_and_communities/api.py @@ -1910,13 +1910,14 @@ def reinstate(self, request, *args, **kwargs): def update(self, request, *args, **kwargs): try: - instance = self.get_object() - serializer = SaveSpeciesDocumentSerializer(instance, data=json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception=True) - serializer.save() - instance.add_documents(request) - instance.species.log_user_action(SpeciesUserAction.ACTION_UPDATE_DOCUMENT.format(instance.document_number,instance.species.species_number),request) - return Response(serializer.data) + with transaction.atomic(): + instance = self.get_object() + serializer = SaveSpeciesDocumentSerializer(instance, data=json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception=True) + serializer.save() + instance.add_documents(request) + instance.species.log_user_action(SpeciesUserAction.ACTION_UPDATE_DOCUMENT.format(instance.document_number,instance.species.species_number),request) + return Response(serializer.data) except Exception as e: print(traceback.print_exc()) raise serializers.ValidationError(str(e)) @@ -1924,12 +1925,13 @@ def update(self, request, *args, **kwargs): def create(self, request, *args, **kwargs): try: - serializer = SaveSpeciesDocumentSerializer(data= json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception = True) - instance = serializer.save() - instance.add_documents(request) - instance.species.log_user_action(SpeciesUserAction.ACTION_ADD_DOCUMENT.format(instance.document_number,instance.species.species_number),request) - return Response(serializer.data) + with transaction.atomic(): + serializer = SaveSpeciesDocumentSerializer(data= json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception = True) + instance = serializer.save() + instance.add_documents(request) + instance.species.log_user_action(SpeciesUserAction.ACTION_ADD_DOCUMENT.format(instance.document_number,instance.species.species_number),request) + return Response(serializer.data) except serializers.ValidationError: print(traceback.print_exc()) raise @@ -2005,13 +2007,14 @@ def reinstate(self, request, *args, **kwargs): def update(self, request, *args, **kwargs): try: - instance = self.get_object() - serializer = SaveCommunityDocumentSerializer(instance, data=json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception=True) - serializer.save() - instance.add_documents(request) - instance.community.log_user_action(CommunityUserAction.ACTION_UPDATE_DOCUMENT.format(instance.document_number,instance.community.community_number),request) - return Response(serializer.data) + with transaction.atomic(): + instance = self.get_object() + serializer = SaveCommunityDocumentSerializer(instance, data=json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception=True) + serializer.save() + instance.add_documents(request) + instance.community.log_user_action(CommunityUserAction.ACTION_UPDATE_DOCUMENT.format(instance.document_number,instance.community.community_number),request) + return Response(serializer.data) except Exception as e: print(traceback.print_exc()) raise serializers.ValidationError(str(e)) @@ -2019,12 +2022,13 @@ def update(self, request, *args, **kwargs): def create(self, request, *args, **kwargs): try: - serializer = SaveCommunityDocumentSerializer(data= json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception = True) - instance = serializer.save() - instance.add_documents(request) - instance.community.log_user_action(CommunityUserAction.ACTION_ADD_DOCUMENT.format(instance.document_number,instance.community.community_number),request) - return Response(serializer.data) + with transaction.atomic(): + serializer = SaveCommunityDocumentSerializer(data= json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception = True) + instance = serializer.save() + instance.add_documents(request) + instance.community.log_user_action(CommunityUserAction.ACTION_ADD_DOCUMENT.format(instance.document_number,instance.community.community_number),request) + return Response(serializer.data) except serializers.ValidationError: print(traceback.print_exc()) raise @@ -2127,7 +2131,6 @@ def reinstate(self, request, *args, **kwargs): elif instance.community: instance.community.log_user_action(CommunityUserAction.ACTION_REINSTATE_THREAT.format(instance.threat_number,instance.community.community_number),request) serializer = self.get_serializer(instance) - serializer = self.get_serializer(instance) return Response(serializer.data) except serializers.ValidationError: print(traceback.print_exc()) @@ -2141,16 +2144,17 @@ def reinstate(self, request, *args, **kwargs): def update(self, request, *args, **kwargs): try: - instance = self.get_object() - serializer = SaveConservationThreatSerializer(instance, data=json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception=True) - serializer.save() - if instance.species: - instance.species.log_user_action(SpeciesUserAction.ACTION_UPDATE_THREAT.format(instance.threat_number,instance.species.species_number),request) - elif instance.community: - instance.community.log_user_action(CommunityUserAction.ACTION_UPDATE_THREAT.format(instance.threat_number,instance.community.community_number),request) - serializer = self.get_serializer(instance) - return Response(serializer.data) + with transaction.atomic(): + instance = self.get_object() + serializer = SaveConservationThreatSerializer(instance, data=json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception=True) + serializer.save() + if instance.species: + instance.species.log_user_action(SpeciesUserAction.ACTION_UPDATE_THREAT.format(instance.threat_number,instance.species.species_number),request) + elif instance.community: + instance.community.log_user_action(CommunityUserAction.ACTION_UPDATE_THREAT.format(instance.threat_number,instance.community.community_number),request) + serializer = self.get_serializer(instance) + return Response(serializer.data) except Exception as e: print(traceback.print_exc()) raise serializers.ValidationError(str(e)) @@ -2158,15 +2162,16 @@ def update(self, request, *args, **kwargs): def create(self, request, *args, **kwargs): try: - serializer = SaveConservationThreatSerializer(data= json.loads(request.data.get('data'))) - serializer.is_valid(raise_exception = True) - instance = serializer.save() - if instance.species: - instance.species.log_user_action(SpeciesUserAction.ACTION_ADD_THREAT.format(instance.threat_number,instance.species.species_number),request) - elif instance.community: - instance.community.log_user_action(CommunityUserAction.ACTION_ADD_THREAT.format(instance.threat_number,instance.community.community_number),request) - serializer = self.get_serializer(instance) - return Response(serializer.data) + with transaction.atomic(): + serializer = SaveConservationThreatSerializer(data= json.loads(request.data.get('data'))) + serializer.is_valid(raise_exception = True) + instance = serializer.save() + if instance.species: + instance.species.log_user_action(SpeciesUserAction.ACTION_ADD_THREAT.format(instance.threat_number,instance.species.species_number),request) + elif instance.community: + instance.community.log_user_action(CommunityUserAction.ACTION_ADD_THREAT.format(instance.threat_number,instance.community.community_number),request) + serializer = self.get_serializer(instance) + return Response(serializer.data) except serializers.ValidationError: print(traceback.print_exc()) raise diff --git a/boranga/frontend/boranga/src/api.js b/boranga/frontend/boranga/src/api.js index c9c9510f..a6fcb043 100644 --- a/boranga/frontend/boranga/src/api.js +++ b/boranga/frontend/boranga/src/api.js @@ -142,6 +142,7 @@ module.exports = { occurrence_report:"/api/occurrence_report", observer_detail:"/api/observer_detail.json", occurrence_report_documents:"/api/occurrence_report_documents.json", + ocr_threat:"/api/ocr_threat.json", //approvals_paginated:"/api/approvals/user_list_paginated/?format=datatables", //compliances_paginated:"/api/compliances/user_list_paginated/?format=datatables", diff --git a/boranga/frontend/boranga/src/components/common/occurrence/ocr_threats.vue b/boranga/frontend/boranga/src/components/common/occurrence/ocr_threats.vue new file mode 100644 index 00000000..5581f164 --- /dev/null +++ b/boranga/frontend/boranga/src/components/common/occurrence/ocr_threats.vue @@ -0,0 +1,412 @@ + + + + + diff --git a/boranga/frontend/boranga/src/components/common/species_communities/add_threat.vue b/boranga/frontend/boranga/src/components/common/species_communities/add_threat.vue index cd37b5e1..f97c06f1 100644 --- a/boranga/frontend/boranga/src/components/common/species_communities/add_threat.vue +++ b/boranga/frontend/boranga/src/components/common/species_communities/add_threat.vue @@ -99,13 +99,15 @@
- -