Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
 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")
Ejemplo n.º 4
0
 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")
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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