Beispiel #1
0
    def handle(self, *args, **options):
        path = args[0]

        try:
            username = args[1]
        except IndexError:
            raise CommandError("You must provide the username to publish the forms to.")
        # make sure user exists
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise CommandError("The user '{}' does not exist.".format(username))

        for form in glob.glob( os.path.join(path, "*") ):
            print('Publishing form "{}"...'.format(form))
            f = open(form)
            xml = f.read()
            id_string = get_id_string_from_xml_str(xml)

            # check if a form with this id_string exists for this user
            form_already_exists = XForm.objects.filter(user=user,
                id_string=id_string).count() > 0

            if form_already_exists:
                if options.has_key('replace') and options['replace']:
                    XForm.objects.filter(user=user, id_string=id_string).delete()
                else:
                    raise CommandError('form "{}" is already defined, and --replace was not specified.'.format(
                        id_string))
                if not XForm.can_be_replaced():
                    raise CommandError('form "{}" has submissions of file -- cannot replace'.format(id_string))
            try:
                survey = create_survey_element_from_xml(xml)
            except (AssertionError, TypeError) as e:
                 print(repr(e.args))  # pass on the error message (works in Python 2 and 3)
            else:
                form_json = survey.to_json()
                XForm.objects.get_or_create(xml=xml, downloadable=True, user=user, id_string=id_string, json=form_json)
                print('  (Done).')
            f.close()
            print()
Beispiel #2
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.
    """

    instance = None
    xform = None

    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
        try:
            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

        except XForm.DoesNotExist:
            pass

    # 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)
        if xform is None:
            try:
                xform = XForm.objects.get(id_string=id_string,
                                          user__username=username)
            except XForm.DoesNotExist:
                pass
        if xform is not None:
            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)
    try:
        # make sure the Instance object doesn't already exist
        # using good db optimization practices
        # (https://docs.djangoproject.com/en/1.5/topics/db/optimization/),
        # there is no need to fetch the whole Instance object, when all
        # we need to check for is existence and an attribute in the associated XForm object

        # this code is logically-equivalent to, but more efficient than, the legacy code below it
        xform_pk = Instance.objects.filter(xml=xml,
                                           user=user).values_list('xform',
                                                                  flat=True)[0]
        if XForm.objects.filter(pk=xform_pk).values_list('has_start_time',
                                                         flat=True)[0]:
            raise DuplicateInstance()

        # don't do it this way, kids, especially with 2.8 million Instances and counting...
        #existing_instance = Instance.objects.filter(xml=xml, user=user)[0]
        #if existing_instance.xform and existing_instance.xform.has_start_time:
        #raise DuplicateInstance()
    except IndexError:
        pass

    # get new and deprecated uuids
    new_uuid = get_uuid_from_xml(xml)
    if new_uuid is not None:
        # this xml is a duplicate, however, there may be
        # new attachments, so save them
        try:
            # here, too, all we need is the pk so don't retrieve the whole object
            duplicate_instance_pk = Instance.objects.filter(
                uuid=new_uuid).values_list('pk', flat=True)[0]
            if media_files:
                _save_attachments.delay(duplicate_instance_pk, media_files)
            raise DuplicateInstance()
        except IndexError:
            pass

    # proceed_to_create_instance = True (as per legacy logic)

    # check if its an edit submission
    old_uuid = get_deprecated_uuid_from_xml(xml)
    if old_uuid is not None:
        try:
            # here is a case where we do need the whole instance, so stet this code
            instance = Instance.objects.filter(uuid=old_uuid)[0]
        except IndexError:
            pass

    if not date_created_override:
        date_created_override = get_submission_date_from_xml(xml)

    if instance is not None:
        # this is an edit
        InstanceHistory.objects.create(xml=instance.xml,
                                       xform_instance=instance,
                                       uuid=old_uuid)
        instance.xml = xml
        instance.uuid = new_uuid
    else:
        # new submission
        instance = Instance.objects.create(xml=xml, user=user, status=status)

    # 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)

    if media_files:
        _save_attachments.delay(instance.pk, media_files)

    return instance
Beispiel #3
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 fomr 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
Beispiel #4
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 fomr 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
Beispiel #5
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.
    """

    instance = None
    xform    = None

    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
        try:
            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

        except XForm.DoesNotExist:
            pass

    # 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)
        if xform is None:
            try:
                xform = XForm.objects.get(id_string=id_string, user__username=username)
            except XForm.DoesNotExist:
                pass
        if xform is not None:
            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)
    try:
        # make sure the Instance object doesn't already exist
        # using good db optimization practices
        # (https://docs.djangoproject.com/en/1.5/topics/db/optimization/),
        # there is no need to fetch the whole Instance object, when all
        # we need to check for is existence and an attribute in the associated XForm object

        # this code is logically-equivalent to, but more efficient than, the legacy code below it
        xform_pk = Instance.objects.filter(xml=xml, user=user).values_list('xform', flat=True)[0]
        if XForm.objects.filter(pk=xform_pk).values_list('has_start_time', flat=True)[0]:
            raise DuplicateInstance()

        # don't do it this way, kids, especially with 2.8 million Instances and counting...
        #existing_instance = Instance.objects.filter(xml=xml, user=user)[0]
        #if existing_instance.xform and existing_instance.xform.has_start_time:
            #raise DuplicateInstance()
    except IndexError:
        pass

    # get new and deprecated uuids
    new_uuid = get_uuid_from_xml(xml)
    if new_uuid is not None:
        # this xml is a duplicate, however, there may be
        # new attachments, so save them
        try:
            # here, too, all we need is the pk so don't retrieve the whole object
            duplicate_instance_pk = Instance.objects.filter(uuid=new_uuid).values_list('pk', flat=True)[0]
            if media_files:
                _save_attachments.delay(duplicate_instance_pk, media_files)
            raise DuplicateInstance()
        except IndexError:
            pass

    # proceed_to_create_instance = True (as per legacy logic)

    # check if its an edit submission
    old_uuid = get_deprecated_uuid_from_xml(xml)
    if old_uuid is not None:
        try:
            # here is a case where we do need the whole instance, so stet this code
            instance = Instance.objects.filter(uuid=old_uuid)[0]
        except IndexError:
            pass

    if not date_created_override:
        date_created_override = get_submission_date_from_xml(xml)

    if instance is not None:
        # this is an edit
        InstanceHistory.objects.create(
            xml=instance.xml, xform_instance=instance, uuid=old_uuid)
        instance.xml = xml
        instance.uuid = new_uuid
    else:
        # new submission
        instance = Instance.objects.create(
            xml=xml, user=user, status=status)

    # 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)

    if media_files:
        _save_attachments.delay(instance.pk, media_files)

    return instance