def _get_instance(xml, new_uuid, submitted_by, status, xform): history = None instance = None # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) if old_uuid: instance = Instance.objects.filter(uuid=old_uuid).first() history = InstanceHistory.objects.filter( xform_instance__xform=xform, uuid=new_uuid ).only('xform_instance').first() if instance: # edits check_edit_submission_permissions(submitted_by, xform) last_edited = timezone.now() InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid, user=submitted_by, geom=instance.geom, submission_date=instance.last_edited or instance.date_created) instance.xml = xml instance.last_edited = last_edited instance.uuid = new_uuid instance.save() elif history: instance = history.xform_instance if old_uuid is None or (instance is None and history is None): # new submission instance = Instance.objects.create( xml=xml, user=submitted_by, status=status, xform=xform) return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform, checksum, request=None): history = None instance = None message_verb = SUBMISSION_EDITED # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) if old_uuid: instance = Instance.objects.filter(uuid=old_uuid, xform_id=xform.pk).first() history = InstanceHistory.objects.filter( xform_instance__xform_id=xform.pk, uuid=new_uuid).only('xform_instance').first() if instance: # edits check_edit_submission_permissions(submitted_by, xform) last_edited = timezone.now() InstanceHistory.objects.create(checksum=instance.checksum, xml=instance.xml, xform_instance=instance, uuid=old_uuid, user=submitted_by, geom=instance.geom, submission_date=instance.last_edited or instance.date_created) instance.xml = xml instance.last_edited = last_edited instance.uuid = new_uuid instance.checksum = checksum instance.save() # call webhooks process_submission.send(sender=instance.__class__, instance=instance) elif history: instance = history.xform_instance if old_uuid is None or (instance is None and history is None): # new submission message_verb = SUBMISSION_CREATED instance = Instance.objects.create(xml=xml, user=submitted_by, status=status, xform=xform, checksum=checksum) # send notification on submission creation send_message(instance_id=instance.id, target_id=instance.xform.id, target_type=XFORM, user=instance.user or instance.xform.user, message_verb=message_verb) return instance
def test_get_deprecated_uuid_from_xml(self): with open( os.path.join(os.path.dirname(__file__), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml"), "r") as xml_file: xml_str = xml_file.read() deprecatedID = get_deprecated_uuid_from_xml(xml_str) self.assertEqual(deprecatedID, "729f173c688e482486a48661700455ff")
def test_get_deprecated_uuid_from_xml(self): with open( os.path.join( os.path.dirname(__file__), "..", "fixtures", "tutorial", "instances", "tutorial_2012-06-27_11-27-53_w_uuid_edited.xml"), "r") as xml_file: xml_str = xml_file.read() deprecatedID = get_deprecated_uuid_from_xml(xml_str) self.assertEqual(deprecatedID, "729f173c688e482486a48661700455ff")
def _get_instance( request: 'rest_framework.request.Request', xml: str, new_uuid: str, status: str, xform: XForm, defer_counting: bool = False, ) -> Instance: """ `defer_counting=False` will set a Python-only attribute of the same name on the *new* `Instance` if one is created. This will prevent `update_xform_submission_count()` from doing anything, which avoids locking any rows in `logger_xform` or `main_userprofile`. """ # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if instances: # edits instance = instances[0] check_edit_submission_permissions(request, xform, instance) InstanceHistory.objects.create(xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance._populate_xml_hash() instance.uuid = new_uuid instance.save() else: submitted_by = (request.user if request and request.user.is_authenticated else None) # new submission # Avoid `Instance.objects.create()` so that we can set a Python-only # attribute, `defer_counting`, before saving instance = Instance() instance.xml = xml instance.user = submitted_by instance.status = status instance.xform = xform if defer_counting: # Only set the attribute if requested, i.e. don't bother ever # setting it to `False` instance.defer_counting = True instance.save() return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform, defer_counting=False): ''' `defer_counting=False` will set a Python-only attribute of the same name on the *new* `Instance` if one is created. This will prevent `update_xform_submission_count()` from doing anything, which avoids locking any rows in `logger_xform` or `main_userprofile`. ''' # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if instances: # edits check_edit_submission_permissions(submitted_by, xform) instance = instances[0] InstanceHistory.objects.create(xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance._populate_xml_hash() instance.uuid = new_uuid instance.save() else: # new submission # Avoid `Instance.objects.create()` so that we can set a Python-only # attribute, `defer_counting`, before saving instance = Instance() instance.xml = xml instance.user = submitted_by instance.status = status instance.xform = xform if defer_counting: # Only set the attribute if requested, i.e. don't bother ever # setting it to `False` instance.defer_counting = True instance.save() return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform, checksum): history = None instance = None # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) if old_uuid: instance = Instance.objects.filter(uuid=old_uuid, xform_id=xform.pk).first() history = InstanceHistory.objects.filter( xform_instance__xform_id=xform.pk, uuid=new_uuid).only('xform_instance').first() if instance: # edits check_edit_submission_permissions(submitted_by, xform) last_edited = timezone.now() InstanceHistory.objects.create( checksum=instance.checksum, xml=instance.xml, xform_instance=instance, uuid=old_uuid, user=submitted_by, geom=instance.geom, submission_date=instance.last_edited or instance.date_created) instance.xml = xml instance.last_edited = last_edited instance.uuid = new_uuid instance.checksum = checksum instance.save() # call webhooks process_submission.send(sender=instance.__class__, instance=instance) elif history: instance = history.xform_instance if old_uuid is None or (instance is None and history is None): # new submission instance = Instance.objects.create( xml=xml, user=submitted_by, status=status, xform=xform, checksum=checksum) return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform): # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if instances: # edits check_edit_submission_permissions(submitted_by, xform) instance = instances[0] InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance.uuid = new_uuid instance.save() else: # new submission instance = Instance.objects.create( xml=xml, user=submitted_by, status=status, xform=xform) return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform): # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if instances: # edits check_edit_submission_permissions(submitted_by, xform) instance = instances[0] InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance.uuid = new_uuid instance.save() else: # new submission instance = Instance.objects.create( xml=xml, user=submitted_by, status=status, xform=xform) return instance
def _get_instance(xml, new_uuid, submitted_by, status, xform, defer_counting=False): ''' `defer_counting=False` will set a Python-only attribute of the same name on the *new* `Instance` if one is created. This will prevent `update_xform_submission_count()` from doing anything, which avoids locking any rows in `logger_xform` or `main_userprofile`. ''' # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if instances: # edits check_edit_submission_permissions(submitted_by, xform) instance = instances[0] InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance._populate_xml_hash() instance.uuid = new_uuid instance.save() else: # new submission # Avoid `Instance.objects.create()` so that we can set a Python-only # attribute, `defer_counting`, before saving instance = Instance() instance.xml = xml instance.user = submitted_by instance.status = status instance.xform = xform if defer_counting: # Only set the attribute if requested, i.e. don't bother ever # setting it to `False` instance.defer_counting = True instance.save() return instance
def create_instance(username, xml_file, media_files, status=u'submitted_via_web', uuid=None, date_created_override=None, request=None): """ I used to check if this file had been submitted already, I've taken this out because it was too slow. Now we're going to create a way for an admin to mark duplicate instances. This should simplify things a bit. Submission cases: If there is a username and no uuid, submitting an old ODK form. If there is no username and a uuid, submitting a touchform. If there is a username and a uuid, submitting a new ODK form. """ try: if username: username = username.lower() xml = xml_file.read() is_touchform = False # check alternative form submission ids if not uuid: # parse UUID from uploaded XML split_xml = uuid_regex.split(xml) # check that xml has UUID, then it is a crowdform if len(split_xml) > 1: uuid = split_xml[1] else: # is a touchform is_touchform = True if not username and not uuid: raise InstanceInvalidUserError() if uuid: # try find the form by its uuid which is the ideal condition if XForm.objects.filter(uuid=uuid).count() > 0: xform = XForm.objects.get(uuid=uuid) xform_username = xform.user.username if xform_username != username and not xform.is_crowd_form \ and not is_touchform: raise IsNotCrowdformError() username = xform_username # Else, since we have a username, the Instance creation logic will # handle checking for the forms existence by its id_string if username and request and request.user.is_authenticated(): id_string = get_id_string_from_xml_str(xml) xform = XForm.objects.get( id_string=id_string, user__username=username) if not xform.is_crowd_form and not is_touchform \ and xform.user.profile.require_auth \ and xform.user != request.user: raise PermissionDenied( _(u"%(request_user)s is not allowed to make submissions " u"to %(form_user)s's %(form_title)s form." % { 'request_user': request.user, 'form_user': xform.user, 'form_title': xform.title})) user = get_object_or_404(User, username=username) existing_instance_count = Instance.objects.filter( xml=xml, user=user).count() if existing_instance_count == 0: proceed_to_create_instance = True else: existing_instance = Instance.objects.filter(xml=xml, user=user)[0] if existing_instance.xform and\ not existing_instance.xform.has_start_time: proceed_to_create_instance = True else: # Ignore submission as a duplicate IFF # * a submission's XForm collects start time # * the submitted XML is an exact match with one that # has already been submitted for that user. proceed_to_create_instance = False raise DuplicateInstance() # get new and depracated uuid's new_uuid = get_uuid_from_xml(xml) duplicate_instances = Instance.objects.filter(uuid=new_uuid) if duplicate_instances: for f in media_files: Attachment.objects.get_or_create( instance=duplicate_instances[0], media_file=f, mimetype=f.content_type) # ensure we have saved the extra attachments transaction.commit() raise DuplicateInstance() if proceed_to_create_instance: # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if not date_created_override: date_created_override = get_submission_date_from_xml(xml) if instances: instance = instances[0] InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance.uuid = new_uuid instance.save() else: # new submission instance = Instance.objects.create( xml=xml, user=user, status=status) for f in media_files: Attachment.objects.get_or_create( instance=instance, media_file=f, mimetype=f.content_type) # override date created if required if date_created_override: if not timezone.is_aware(date_created_override): # default to utc? date_created_override = timezone.make_aware( date_created_override, timezone.utc) instance.date_created = date_created_override instance.save() if instance.xform is not None: pi, created = ParsedInstance.objects.get_or_create( instance=instance) if not created: pi.save(async=False) # commit all changes transaction.commit() return instance except Exception: transaction.rollback() raise return None
def create_instance(username, xml_file, media_files, status=u'submitted_via_web', uuid=None, date_created_override=None, request=None): """ I used to check if this file had been submitted already, I've taken this out because it was too slow. Now we're going to create a way for an admin to mark duplicate instances. This should simplify things a bit. Submission cases: If there is a username and no uuid, submitting an old ODK form. If there is no username and a uuid, submitting a touchform. If there is a username and a uuid, submitting a new ODK form. """ try: if username: username = username.lower() xml = xml_file.read() is_touchform = False # check alternative form submission ids if not uuid: # parse UUID from uploaded XML split_xml = uuid_regex.split(xml) # check that xml has UUID, then it is a crowdform if len(split_xml) > 1: uuid = split_xml[1] else: # is a touchform is_touchform = True if not username and not uuid: raise InstanceInvalidUserError() if uuid: # try find the form by its uuid which is the ideal condition if XForm.objects.filter(uuid=uuid).count() > 0: xform = XForm.objects.get(uuid=uuid) xform_username = xform.user.username if xform_username != username and not xform.is_crowd_form \ and not is_touchform: raise IsNotCrowdformError() username = xform_username # Else, since we have a username, the Instance creation logic will # handle checking for the forms existence by its id_string if username and request and request.user.is_authenticated(): id_string = get_id_string_from_xml_str(xml) xform = XForm.objects.get( id_string=id_string, user__username=username) if not xform.is_crowd_form and not is_touchform \ and xform.user.profile.require_auth \ and xform.user != request.user: raise PermissionDenied( _(u"%(request_user)s is not allowed to make submissions " u"to %(form_user)s's %(form_title)s form." % { 'request_user': request.user, 'form_user': xform.user, 'form_title': xform.title})) user = get_object_or_404(User, username=username) existing_instance_count = Instance.objects.filter( xml=xml, user=user).count() if existing_instance_count == 0: proceed_to_create_instance = True else: existing_instance = Instance.objects.filter(xml=xml, user=user)[0] if existing_instance.xform and\ not existing_instance.xform.has_start_time: proceed_to_create_instance = True else: # Ignore submission as a duplicate IFF # * a submission's XForm collects start time # * the submitted XML is an exact match with one that # has already been submitted for that user. proceed_to_create_instance = False raise DuplicateInstance() # get new and depracated uuid's new_uuid = get_uuid_from_xml(xml) duplicate_instances = Instance.objects.filter(uuid=new_uuid) if duplicate_instances: for f in media_files: Attachment.objects.get_or_create( instance=duplicate_instances[0], media_file=f, mimetype=f.content_type) # ensure we have saved the extra attachments transaction.commit() raise DuplicateInstance() if proceed_to_create_instance: # check if its an edit submission old_uuid = get_deprecated_uuid_from_xml(xml) instances = Instance.objects.filter(uuid=old_uuid) if not date_created_override: date_created_override = get_submission_date_from_xml(xml) if instances: instance = instances[0] InstanceHistory.objects.create( xml=instance.xml, xform_instance=instance, uuid=old_uuid) instance.xml = xml instance.uuid = new_uuid instance.save() else: # new submission instance = Instance.objects.create( xml=xml, user=user, status=status) for f in media_files: Attachment.objects.get_or_create( instance=instance, media_file=f, mimetype=f.content_type) # override date created if required if date_created_override: if not timezone.is_aware(date_created_override): # default to utc? date_created_override = timezone.make_aware( date_created_override, timezone.utc) instance.date_created = date_created_override instance.save() if instance.xform is not None: pi, created = ParsedInstance.objects.get_or_create( instance=instance) if not created: pi.save(async=False) # commit all changes transaction.commit() return instance except Exception: transaction.rollback() raise return None