Skip to content

Commit

Permalink
Feature delete records by source reference id (#3649)
Browse files Browse the repository at this point in the history
* Add button

* Feature to delete records by source reference id
  • Loading branch information
dimasciput authored Dec 28, 2023
1 parent 896eea6 commit 5a1aecd
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 94 deletions.
8 changes: 6 additions & 2 deletions bims/api_urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.urls import re_path, include, path

from bims.api_views.reference import DeleteRecordsByReferenceId
# from rest_framework.documentation import include_docs_urls
from bims.api_views.boundary import (
BoundaryList,
Expand Down Expand Up @@ -320,8 +322,10 @@
),
re_path(r'^gbif-ids/download/$',
GbifIdsDownloader.as_view()),

path('download-layer-data/<int:layer_id>/<str:query_filter>/',
DownloadLayerData.as_view(),
name='download-layer-data')
name='download-layer-data'),
path('delete-records-by-source-reference-id/<int:source_reference_id>/',
DeleteRecordsByReferenceId.as_view(),
name='delete-records-by-source-reference-id')
]
68 changes: 68 additions & 0 deletions bims/api_views/reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from django.http import (
Http404, HttpResponseServerError, HttpResponseForbidden
)
from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from bims.models.source_reference import (
SourceReference
)
from bims.models.biological_collection_record import (
BiologicalCollectionRecord
)
from bims.models.chemical_record import (
ChemicalRecord
)
from bims.models.decision_support_tool import DecisionSupportTool


class DeleteRecordsByReferenceId(APIView):
"""
API endpoint for deleting BiologicalCollectionRecord and ChemicalRecord
instances associated with a given SourceReference ID.
"""

def post(self, request, *args, **kwargs):
if not request.user.is_superuser:
return HttpResponseForbidden(
'Only superusers are allowed to perform this action.'
)

source_reference_id = kwargs.get('source_reference_id')
if not source_reference_id:
raise Http404('Missing id')

try:
source_reference = get_object_or_404(
SourceReference,
pk=source_reference_id
)
messages = []
bio_records = BiologicalCollectionRecord.objects.filter(source_reference_id=source_reference_id)
if bio_records.exists():
DecisionSupportTool.objects.filter(
biological_collection_record__id__in=list(bio_records.values_list('id', flat=True))
).delete()
BiologicalCollectionRecord.objects.filter(source_reference_id=source_reference_id).delete()
messages.append(
'BiologicalCollectionRecord successfully deleted'
)
else:
messages.append("No BiologicalCollectionRecord found for the given reference ID.")

if ChemicalRecord.objects.filter(source_reference_id=source_reference_id).exists():
ChemicalRecord.objects.filter(source_reference_id=source_reference_id).delete()
messages.append(
'ChemicalRecord successfully deleted'
)
else:
messages.append("No ChemicalRecord found for the given reference ID.")

return Response(
{'message': messages},
status=status.HTTP_200_OK)

except Exception as e:
# In case of any other error, return a 500 Internal Server Error
return HttpResponseServerError(f'An error occurred: {e}')
5 changes: 4 additions & 1 deletion bims/models/decision_support_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ class DecisionSupportTool(models.Model):
)

def __str__(self):
return f'{self.name} - {self.biological_collection_record.uuid}'
try:
return f'{self.name} - {self.biological_collection_record.uuid}'
except Exception as e:
return f'{self.name}'
2 changes: 1 addition & 1 deletion bims/models/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import uuid

from django.db import models
from django.db.models.signals import post_delete, pre_delete
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.utils import timezone
from bims.models import LocationSite
Expand Down
59 changes: 59 additions & 0 deletions bims/static/css/source_reference_list.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.card {
margin-bottom: 10px;
}

.custom-control-label {
max-width: 80%;
}

.reference-filter-title {
margin-bottom: 0 !important;
font-weight: bold;
}
.badge-occurrences {
font-size: 9pt;
padding-left: 10px;
padding-right: 10px;
padding-top: 8px;
padding-bottom: 8px;
}
.badge-zero {
background-color: #b8b8b8;
}
.reference-type-label {
text-transform: uppercase;
font-weight: 300;
font-size: 10pt;
}
.active.active:hover {
color: white;
}
.input-group-append:hover {
cursor: pointer;
}
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}

.loader {
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 2s linear infinite;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
76 changes: 76 additions & 0 deletions bims/static/js/non_requirejs/source_reference_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
$('.copy-document-id').click(function (e) {
let documentId = window.location.origin + '/documents/' + $(e.target).data('document-id');
/* Copy the text inside the text field */
navigator.clipboard.writeText(documentId);
/* Alert the copied text */
alert("Copied the text: " + documentId);
})

$('.custom-control-input').change(function (e) {
let $parent = $(e.target).parent().parent();
let filterName = $parent.data('filter');
let checkedVals = $parent.find(':checkbox:checked').map(function () {
return this.value;
}).get();
insertParam(filterName, checkedVals);
})

$('.input-group-append').click(function (e) {
let value = $('#search-input').val();
insertParam('q', value);
})

$('.delete-reference').click(function (e) {
e.preventDefault();
const referenceId = $(e.target).data('reference-id');
let r = confirm("Are you sure you want to remove this reference?");
if (r === true) {
$.ajax({
url: "/delete-source-reference/",
headers: {"X-CSRFToken": csrfToken},
type: 'POST',
data: {
'reference_id': referenceId
},
success: function (res) {
location.reload();
}
});
}
})

$('.delete-records').click(function (e) {
e.preventDefault();
const referenceId = $(e.target).data('reference-id');
const totalRecords = $(e.target).data('total-records');
const totalPhysico = $(e.target).data('total-physico-chemical-data');
let r = confirm(
`Are you sure you want to remove ${totalRecords} records and ${totalPhysico}
Physico-chemical data associated with this source reference?`);
if (r) {
document.getElementById('loading-animation').style.display = 'flex';
console.log('called');
$.ajax({
url: `/api/delete-records-by-source-reference-id/${referenceId}/`,
type: 'POST',
headers: {"X-CSRFToken": csrfToken},
success: function(response) {
window.location.reload();
},
error: function(xhr, textStatus, errorThrown) {
alert('Error: ' + errorThrown);
document.getElementById('loading-animation').style.display = 'none';
}
});
}

})


$('.apply-author-filter').click(function(e) {
const $target = $(e.target).parent();
const authorIds = $target.find('.author_result').map(function () {
return $(this).data("author-id");
}).get();
insertParam('collectors', authorIds.join(','))
})
107 changes: 20 additions & 87 deletions bims/templates/source_reference_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,16 @@
{% block pre-head %}
<link rel="stylesheet"
href="{% static "lib/select2-4.1.0/css/select2.min.css" %}">
<style>
.card {
margin-bottom: 10px;
}

.custom-control-label {
max-width: 80%;
}

.reference-filter-title {
margin-bottom: 0 !important;
font-weight: bold;
}
.badge-occurrences {
font-size: 9pt;
padding-left: 10px;
padding-right: 10px;
padding-top: 8px;
padding-bottom: 8px;
}
.badge-zero {
background-color: #b8b8b8;
}
.reference-type-label {
text-transform: uppercase;
font-weight: 300;
font-size: 10pt;
}
.active.active:hover {
color: white;
}
.input-group-append:hover {
cursor: pointer;
}
</style>
<link rel="stylesheet"
href="{% static "css/source_reference_list.css" %}">
{% endblock %}

{% block body_content %}
<!-- Page Header -->
<div id="loading-animation" class="loading-container">
<!-- Here, you can use an image or any animation you like -->
<div class="loader"></div>
</div>
<div class="body-container container">
<div class="dashboard-title">
<h2>Explore Source References&nbsp;<span class="vertical-separator"></span>{{ page_obj.paginator.count }} Result{% if page_obj.paginator.count > 1 %}s{% endif %}</h2>
Expand Down Expand Up @@ -150,8 +121,17 @@ <h5 class="card-title">{{ source_reference.link_template | safe }}</h5>
<a href="/edit-source-reference/{{ source_reference.id }}/?next={{ request.get_full_path | urlencode }}" class="badge badge-primary badge-occurrences">Update</a>
</div>
<div class="float-right">
<a href="#" class="badge badge-danger badge-occurrences delete-reference" data-reference-id="{{ source_reference.id }}">Delete</a>&nbsp;
<a href="#" class="badge badge-danger badge-occurrences delete-reference" data-reference-id="{{ source_reference.id }}">Delete source reference</a>&nbsp;
</div>
{% if source_reference.occurrences > 0 or source_reference.chemical_records > 0 %}
<div class="float-right">
<a href="#" class="badge badge-warning badge-occurrences delete-records"
data-reference-id="{{ source_reference.id }}"
data-total-physico-chemical-data="{{ source_reference.chemical_records }}"
data-total-records="{{ source_reference.occurrences }}"
>Delete records</a>&nbsp;
</div>
{% endif %}
{% endif %}
</div>
</div>
Expand All @@ -176,58 +156,11 @@ <h5 class="card-title">{{ source_reference.link_template | safe }}</h5>
<script src="{% static "js/utils/insert_param_to_url.js" %}"></script>
<script src="{% static "js/non_requirejs/multi_author_select.js" %}"></script>
<script>

const csrfToken = '{{ csrf_token }}';
const authorIds = [];

$('.copy-document-id').click(function (e) {
let documentId = window.location.origin + '/documents/' + $(e.target).data('document-id');
/* Copy the text inside the text field */
navigator.clipboard.writeText(documentId);
/* Alert the copied text */
alert("Copied the text: " + documentId);
})

$('.custom-control-input').change(function (e) {
let $parent = $(e.target).parent().parent();
let filterName = $parent.data('filter');
let checkedVals = $parent.find(':checkbox:checked').map(function () {
return this.value;
}).get();
insertParam(filterName, checkedVals);
})

$('.input-group-append').click(function (e) {
let value = $('#search-input').val();
insertParam('q', value);
})

$('.delete-reference').click(function (e) {
e.preventDefault();
const referenceId = $(e.target).data('reference-id');
let r = confirm("Are you sure you want to remove this reference?");
if (r === true) {
$.ajax({
url: "/delete-source-reference/",
headers: {"X-CSRFToken": csrfToken},
type: 'POST',
data: {
'reference_id': referenceId
},
success: function (res) {
location.reload();
}
});
}
})

$('.apply-author-filter').click(function(e) {
const $target = $(e.target).parent();
const authorIds = $target.find('.author_result').map(function () {
return $(this).data("author-id");
}).get();
insertParam('collectors', authorIds.join(','))
})

window.onload = function() {
document.getElementById('loading-animation').style.display = 'none';
};
</script>
<script src="{% static "js/non_requirejs/source_reference_list.js" %}"></script>
{% endblock %}
Loading

0 comments on commit 5a1aecd

Please sign in to comment.