Skip to content

Commit

Permalink
Merge pull request #58 from c3g/curation-entity-attribute
Browse files Browse the repository at this point in the history
Curation entity attribute
  • Loading branch information
UlysseFG authored May 11, 2021
2 parents 99dd9c8 + 238242c commit b5d7bec
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 3 deletions.
89 changes: 89 additions & 0 deletions backend/fms_core/management/commands/_update_field_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from django.apps import apps
import reversion
import json
import logging
from reversion.models import Version
from fms_core.models import *

# Parameters required for this curation
ACTION = "action" # = update_field_value
CURATION_INDEX = "curation_index" # Number indicating the order in which this action was performed during the curation.
COMMENT = "comment" # An optional comment to be stored in the logs
ENTITY_MODEL = "entity_model" # The name of the model for the target entity.
ENTITY_DICT_ID = "entity_identifier" # An array of dictionary that contains the fields required to uniquely identify the targeted entity.
FIELD_NAME = "field_name" # The name of the field that need to be updated.
VALUE_OLD = "value_old" # The old value of the entity's field (used for validation). Optional, validation skipped if empty.
VALUE_NEW = "value_new" # The new value of the entity's field.
USER_ID = "requester_user_id" # The user id of the person requesting the curation. Optional, if left empty use biobankadmin id.

# Curation params template
# { CURATION_INDEX: 1,
# ACTION: "update_field_value",
# COMMENT: "Dr. No asled the samples to be changed from BLOOD to PLASMA to correct an error at submission.",
# ENTITY_MODEL: "Sample",
# ENTITY_DICT_ID: [{"name": "Sample_test", "id": 42, "container_id": 5823}], # Any subset of fields that identifies uniquely the entity
# FIELD_NAME: "sample_kind",
# VALUE_OLD: 5, # Matches BLOOD
# VALUE_NEW: 9, # Matches PLASMA
# USER_ID: 5
# }

# ENTITY_DICT_ID is an array to allow an identical change to be performed on multiple entities. If the changes are different,
# add more field_value_actions to the curation.

def update_field_value(params, log):
log.info("Action [" + str(params[CURATION_INDEX]) + "] Update Field Value started.")
log.info("Comment [" + str(params.get(COMMENT, "None")) + "].")
log.info("Targeted model : " + str(params[ENTITY_MODEL]))
log.info("Identifier used : " + str(params[ENTITY_DICT_ID]))
log.info("Field to update : " + str(params[FIELD_NAME]))
log.info("Old value : " + str(params.get(VALUE_OLD)))
log.info("New value : " + str(params[VALUE_NEW]))
log.info("Requester id : " + str(params.get(USER_ID)))

# initialize the curation
curation_code = params.get(CURATION_INDEX, "Invalid index")
error_found = False
model = params[ENTITY_MODEL]
id_array = params[ENTITY_DICT_ID]
field = params[FIELD_NAME]
old_value = params.get(VALUE_OLD)
new_value = params[VALUE_NEW]
user_id = params.get(USER_ID)


try:
entity_model = apps.get_model("fms_core", model)
count_updates = 0
for id in id_array:
try:
entity = entity_model.objects.get(**id)
try:
db_old_value = getattr(entity, field)
if old_value and old_value == db_old_value:
setattr(entity, field, new_value)
log.info(f"Updated model [{model}] id [{id} field [{field}] old value [{old_value}] new value [{new_value}].")
if user_id:
entity.save(requester_id=user_id) # Save using th id of the requester
else:
entity.save() # Save using the default admin user
count_updates += 1
else:
log.error(f"Content of field [{field}] do not match the old_value expected [{old_value}].")
error_found = True
except AttributeError:
log.error(f"Field [{field}] does not exist for model [{model}].")
error_found = True
except entity_model.DoesNotExist:
log.error(f"No entity found for id [{id}].")
error_found = True
except entity_model.MultipleObjectsReturned:
log.error(f"Multiple entities found for id [{id}]. Provide a unique identifier.")
error_found = True
except LookupError as e:
log.error("Model [" + str(model) + "] does not exist.")
error_found = True
if not error_found:
curation_code = None
log.info(f"Updated [{count_updates}] field values.")
return curation_code
5 changes: 4 additions & 1 deletion backend/fms_core/management/commands/curation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
# Import the functions of the various curations available.
from ._rollback_extraction import rollback_extraction
from ._rollback_curation import rollback_curation
from ._update_field_value import update_field_value

# Available actions
ACTION_ROLLBACK_CURATION = "rollback_curation"
ACTION_ROLLBACK_EXTRACTION = "rollback_extraction"
ACTION_UPDATE_FIELD_VALUE = "update_field_value"

# Curation params template
# [CURATION_ACTION_TEMPLATE_1,CURATION_ACTION_TEMPLATE_2,...]
Expand All @@ -35,7 +37,8 @@ class Command(BaseCommand):

curation_switch = {
ACTION_ROLLBACK_EXTRACTION: rollback_extraction,
ACTION_ROLLBACK_CURATION: rollback_curation
ACTION_ROLLBACK_CURATION: rollback_curation,
ACTION_UPDATE_FIELD_VALUE: update_field_value,
}

def init_logging(self, log_name, timestamp):
Expand Down
8 changes: 6 additions & 2 deletions backend/fms_core/models/tracked_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ class Meta:
abstract = True

def save(self, *args, **kwargs):
user = get_current_user()
requester = kwargs.get("requester_id")
if requester:
user = User.objects.get(pk=requester)
else:
user = get_current_user()
if not user or (user and not user.pk):
user = User.objects.get(username=ADMIN_USERNAME)
# if the instance has not been saved to the DB yet
Expand All @@ -29,7 +33,7 @@ def save(self, *args, **kwargs):
# Set modified by user each time we save
self.updated_by = user

super().save(*args, **kwargs)
super().save()

def delete(self, *args, **kwargs):
user = get_current_user()
Expand Down

0 comments on commit b5d7bec

Please sign in to comment.