def modify(self, request, *args, **kwargs): xform = self.get_object() http_status = status.HTTP_200_OK response = {} if request.user.has_perm("validate_xform", xform): owner = xform.user userform_id = "{}_{}".format(owner.username, xform.id_string) query = {ParsedInstance.USERFORM_ID: userform_id} # Query used for MongoDB filter_ = {"xform_id": xform.id} # Filter for Django ORM payload = {} try: payload = json.loads(request.data.get("payload", "{}")) except ValueError: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("Invalid payload")} if http_status == status.HTTP_200_OK: if request.data.get("reset"): new_validation_status_uid = {} else: new_validation_status_uid = payload.get("validation_status.uid") if new_validation_status_uid is None: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("No validation_status.uid provided")} else: # Create new validation_status object new_validation_status = get_validation_status( new_validation_status_uid, xform, request.user.username) # 3 scenarios to update submissions # First scenario / Modify submissions based on user's query if payload.get("query"): # Validate if query is valid. try: query.update(payload.get("query")) except ValueError: raise ParseError(_("Invalid query: %(query)s" % {'query': json.dumps(payload.get("query"))})) query_kwargs = { "query": json.dumps(query), "fields": '["_id"]' } cursor = ParsedInstance.query_mongo_no_paging(**query_kwargs) submissions_ids = [record.get("_id") for record in list(cursor)] filter_.update({"id__in": submissions_ids}) # Second scenario / Modify submissions based on list of ids elif payload.get("submissions_ids"): try: # Use int() to test if list of integers is valid. submissions_ids = payload.get("submissions_ids", []) or_ = {u"$or": [{u"_id": int(submission_id)} for submission_id in submissions_ids]} query.update(or_) except ValueError: raise ParseError(_("Invalid submissions ids: %(submissions_ids)s" % {'submissions_ids': json.dumps(payload.get("submissions_ids"))})) filter_.update({"id__in": submissions_ids}) # Third scenario / Modify all submissions in form, but confirmation param must be among payload elif payload.get("confirm", False) is not True: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("No confirmations provided")} # If everything is OK, submit data to DBs if http_status == status.HTTP_200_OK: # Update Postgres & Mongo updated_records_count = Instance.objects.\ filter(**filter_).update(validation_status=new_validation_status) ParsedInstance.bulk_update_validation_statuses(query, new_validation_status) response = {"detail": _("{} submissions have been updated").format(updated_records_count)} return Response(response, http_status) else: raise PermissionDenied(_(u"You do not have validate permissions."))
def modify(self, request, *args, **kwargs): xform = self.get_object() http_status = status.HTTP_200_OK response = {} if request.user.has_perm("validate_xform", xform): owner = xform.user userform_id = "{}_{}".format(owner.username, xform.id_string) query = {ParsedInstance.USERFORM_ID: userform_id} # Query used for MongoDB filter_ = {"xform_id": xform.id} # Filter for Django ORM payload = {} try: payload = json.loads(request.data.get("payload", "{}")) except ValueError: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("Invalid payload")} if http_status == status.HTTP_200_OK: new_validation_status_uid = payload.get("validation_status.uid") if new_validation_status_uid is None: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("No validation_status.uid provided")} else: # Create new validation_status object new_validation_status = get_validation_status( new_validation_status_uid, xform, request.user.username) # 3 scenarios to update submissions # First scenario / Modify submissions based on user's query if payload.get("query"): # Validate if query is valid. try: query.update(payload.get("query")) except ValueError: raise ParseError(_("Invalid query: %(query)s" % {'query': json.dumps(payload.get("query"))})) query_kwargs = { "query": json.dumps(query), "fields": '["_id"]' } cursor = ParsedInstance.query_mongo_no_paging(**query_kwargs) submissions_ids = [record.get("_id") for record in list(cursor)] filter_.update({"id__in": submissions_ids}) # Second scenario / Modify submissions based on list of ids elif payload.get("submissions_ids"): try: # Use int() to test if list of integers is valid. submissions_ids = payload.get("submissions_ids", []) or_ = {u"$or": [{u"_id": int(submission_id)} for submission_id in submissions_ids]} query.update(or_) except ValueError: raise ParseError(_("Invalid submissions ids: %(submissions_ids)s" % {'submissions_ids': json.dumps(payload.get("submissions_ids"))})) filter_.update({"id__in": submissions_ids}) # Third scenario / Modify all submissions in form, but confirmation param must be among payload elif payload.get("confirm", False) is not True: http_status = status.HTTP_400_BAD_REQUEST response = {"detail": _("No confirmations provided")} # If everything is OK, submit data to DBs if http_status == status.HTTP_200_OK: # Update Postgres & Mongo updated_records_count = Instance.objects.\ filter(**filter_).update(validation_status=new_validation_status) ParsedInstance.bulk_update_validation_statuses(query, new_validation_status) response = {"detail": _("{} submissions have been updated").format(updated_records_count)} return Response(response, http_status) else: raise PermissionDenied(_(u"You do not have validate permissions."))
def __build_db_queries(xform_, payload): """ Gets instance ids based on the request payload. Useful to narrow down set of instances for bulk actions Args: xform_ (XForm) payload (dict) Returns: tuple(<dict>, <dict>): PostgreSQL filters, Mongo filters. They are meant to be used respectively with Django Queryset and PyMongo query. """ mongo_query = ParsedInstance.get_base_query(xform_.user.username, xform_.id_string) postgres_query = {'xform_id': xform_.id} instance_ids = None ################################################### # Submissions can be retrieve in 3 different ways # ################################################### # First of all, users can't mix `query` and `submission_ids` in `payload` if all(key_ in payload for key_ in ('query', 'submission_ids')): raise ValidationError({ 'payload': _("`query` and `instance_ids` can't be used together") }) # First scenario / Get submissions based on user's query try: query = payload['query'] except KeyError: pass else: try: query.update(mongo_query) # Overrides `_userform_id` if exists except AttributeError: raise ValidationError({ 'payload': _('Invalid query: %(query)s') % { 'query': json.dumps(query) } }) query_kwargs = {'query': json.dumps(query), 'fields': '["_id"]'} cursor = ParsedInstance.query_mongo_no_paging(**query_kwargs) instance_ids = [record.get('_id') for record in list(cursor)] # Second scenario / Get submissions based on list of ids try: submission_ids = payload['submission_ids'] except KeyError: pass else: try: # Use int() to test if list of integers is valid. instance_ids = [ int(submission_id) for submission_id in submission_ids ] except ValueError: raise ValidationError({ 'payload': _('Invalid submission ids: %(submission_ids)s') % { 'submission_ids': json.dumps(payload['submission_ids']) } }) if instance_ids is not None: # Narrow down queries with list of ids. postgres_query.update({'id__in': instance_ids}) mongo_query.update({'_id': {'$in': instance_ids}}) elif payload.get('confirm', False) is not True: # Third scenario / get all submissions in form, # but confirmation param must be among payload raise NoConfirmationProvidedException() return postgres_query, mongo_query