예제 #1
0
def restore_backup_from_xml_file(xml_instance_path, username):
    # check if its a valid xml instance
    file_name = os.path.basename(xml_instance_path)
    xml_file = django_file(xml_instance_path,
                           field_name="xml_file",
                           content_type="text/xml")
    media_files = []
    try:
        date_created = _date_created_from_filename(file_name)
    except ValueError as e:
        sys.stderr.write(
            "Couldn't determine date created from filename: '%s'\n" %
            file_name)
        date_created = datetime.now()

    sys.stdout.write("Creating instance from '%s'\n" % file_name)
    try:
        create_instance(username,
                        xml_file,
                        media_files,
                        date_created_override=date_created)
        return 1
    except Exception as e:
        sys.stderr.write("Could not restore %s, create instance said: %s\n" %
                         (file_name, e))
        return 0
예제 #2
0
def restore_backup_from_xml_file(xml_instance_path, username):
    # check if its a valid xml instance
    file_name = os.path.basename(xml_instance_path)
    xml_file = django_file(
        xml_instance_path,
        field_name="xml_file",
        content_type="text/xml")
    media_files = []
    try:
        date_created = _date_created_from_filename(file_name)
    except ValueError:
        sys.stderr.write(
            "Couldn't determine date created from filename: '%s'\n" %
            file_name)
        date_created = datetime.now()

    sys.stdout.write("Creating instance from '%s'\n" % file_name)
    try:
        create_instance(
            username, xml_file, media_files,
            date_created_override=date_created)
        return 1
    except Exception as e:
        sys.stderr.write(
            "Could not restore %s, create instance said: %s\n" %
            (file_name, e))
        return 0
 def _submit_at_hour(self, hour):
     st_xml = '<?xml version=\'1.0\' ?><start_time id="start_time"><st'\
              'art_time>2012-01-11T%d:00:00.000+00</start_time></start'\
              '_time>' % hour
     try:
         create_instance(self.user.username, TempFileProxy(st_xml), [])
     except DuplicateInstance:
         pass
예제 #4
0
 def _submit_at_hour(self, hour):
     st_xml = '<?xml version=\'1.0\' ?><start_time id="start_time"><st'\
              'art_time>2012-01-11T%d:00:00.000+00</start_time></start'\
              '_time>' % hour
     try:
         create_instance(self.user.username, TempFileProxy(st_xml), [])
     except DuplicateInstance:
         pass
예제 #5
0
 def submit_at_hour(hour):
     st_xml = """
     <?xml version='1.0' ?><start_time id="start_time"><start_time>2012-01-11T%d:00:00.000+00</start_time></start_time>
     """.strip() % hour
     try:
         create_instance(self.user.username, TempFileProxy(st_xml), [])
     except DuplicateInstance:
         pass
예제 #6
0
    def test_attachment_tracking(self):
        """
        Test that when a submission with many attachments is made,
        we keep track of the total number of attachments expected
        and if we have received all of them
        """
        md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | image | image1 | Photo |
        |        | image | image2 | Photo |
        """
        self._create_user_and_login()
        self.xform = self._publish_markdown(md, self.user)

        xml_string = """
        <data id="{}">
            <meta>
                <instanceID>uuid:UJ5jSMAJ1Jz4EszdgHy8n851AsKaqBPO5</instanceID>
            </meta>
            <image1>1300221157303.jpg</image1>
            <image2>1300375832136.jpg</image2>
        </data>
        """.format(self.xform.id_string)
        file_path = "{}/apps/logger/tests/Health_2011_03_13."\
                    "xml_2011-03-15_20-30-28/1300221157303"\
                    ".jpg".format(settings.PROJECT_ROOT)
        media_file = django_file(path=file_path,
                                 field_name="image1",
                                 content_type="image/jpeg")
        instance = create_instance(self.user.username,
                                   StringIO(xml_string.strip()),
                                   media_files=[media_file])
        self.assertFalse(instance.json[MEDIA_ALL_RECEIVED])
        self.assertEquals(instance.json[TOTAL_MEDIA], 2)
        self.assertEquals(instance.json[MEDIA_COUNT], 1)
        self.assertEquals(instance.json[TOTAL_MEDIA], instance.total_media)
        self.assertEquals(instance.json[MEDIA_COUNT], instance.media_count)
        self.assertEquals(instance.json[MEDIA_ALL_RECEIVED],
                          instance.media_all_received)
        file2_path = "{}/apps/logger/tests/Water_2011_03_17_2011-03-17_16-29"\
                     "-59/1300375832136.jpg".format(settings.PROJECT_ROOT)
        media2_file = django_file(path=file2_path,
                                  field_name="image2",
                                  content_type="image/jpeg")
        create_instance(self.user.username,
                        StringIO(xml_string.strip()),
                        media_files=[media2_file])
        instance2 = Instance.objects.get(pk=instance.pk)
        self.assertTrue(instance2.json[MEDIA_ALL_RECEIVED])
        self.assertEquals(instance2.json[TOTAL_MEDIA], 2)
        self.assertEquals(instance2.json[MEDIA_COUNT], 2)
        self.assertEquals(instance2.json[TOTAL_MEDIA], instance2.total_media)
        self.assertEquals(instance2.json[MEDIA_COUNT], instance2.media_count)
        self.assertEquals(instance2.json[MEDIA_ALL_RECEIVED],
                          instance2.media_all_received)
예제 #7
0
    def _tutorial_form_submission(self):
        tutorial_folder = os.path.join(
            os.path.dirname(__file__),
            '..', 'fixtures', 'forms', 'tutorial')
        self._publish_xls_file_and_set_xform(os.path.join(tutorial_folder,
                                                          'tutorial.xls'))
        instance_paths = [os.path.join(tutorial_folder, 'instances', i)
                          for i in ['1.xml', '2.xml', '3.xml']]
        for path in instance_paths:
            create_instance(self.user.username, open(path), [])

        self.assertEqual(self.xform.instances.count(), 3)
예제 #8
0
    def test_attachment_tracking_duplicate(self):
        """
        Test that duplicate attachments does not affect if all attachments were
        received.
        """
        md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | image | image1 | Photo |
        |        | image | image2 | Photo |
        """
        self._create_user_and_login()
        self.xform = self._publish_markdown(md, self.user)

        xml_string = """
        <data id="{}">
            <meta>
                <instanceID>uuid:UJ5jSMAJ1Jz4EszdgHy8n851AsKaqBPO5</instanceID>
            </meta>
            <image1>1300221157303.jpg</image1>
            <image2>1300375832136.jpg</image2>
        </data>
        """.format(self.xform.id_string)
        file_path = "{}/apps/logger/tests/Health_2011_03_13."\
                    "xml_2011-03-15_20-30-28/1300221157303"\
                    ".jpg".format(settings.PROJECT_ROOT)
        media_file = django_file(path=file_path,
                                 field_name="image1",
                                 content_type="image/jpeg")
        instance = create_instance(self.user.username,
                                   BytesIO(xml_string.strip().encode('utf-8')),
                                   media_files=[media_file])
        self.assertFalse(instance.json[MEDIA_ALL_RECEIVED])
        self.assertEquals(instance.json[TOTAL_MEDIA], 2)
        self.assertEquals(instance.json[MEDIA_COUNT], 1)
        self.assertEquals(instance.json[TOTAL_MEDIA], instance.total_media)
        self.assertEquals(instance.json[MEDIA_COUNT], instance.media_count)
        self.assertEquals(instance.json[MEDIA_ALL_RECEIVED],
                          instance.media_all_received)
        media2_file = django_file(path=file_path,
                                  field_name="image1",
                                  content_type="image/jpeg")
        create_instance(self.user.username,
                        BytesIO(xml_string.strip().encode('utf-8')),
                        media_files=[media2_file])
        instance2 = Instance.objects.get(pk=instance.pk)
        self.assertFalse(instance2.json[MEDIA_ALL_RECEIVED])
        self.assertEquals(instance2.json[TOTAL_MEDIA], 2)
        self.assertEquals(instance2.json[MEDIA_COUNT], 1)
        self.assertEquals(instance2.json[TOTAL_MEDIA], instance2.total_media)
        self.assertEquals(instance2.json[MEDIA_COUNT], instance2.media_count)
        self.assertEquals(instance2.json[MEDIA_ALL_RECEIVED],
                          instance2.media_all_received)
예제 #9
0
    def _tutorial_form_submission(self):
        tutorial_folder = os.path.join(
            os.path.dirname(__file__),
            '..', 'fixtures', 'forms', 'tutorial')
        self._publish_xls_file_and_set_xform(os.path.join(tutorial_folder,
                                                          'tutorial.xls'))
        instance_paths = [os.path.join(tutorial_folder, 'instances', i)
                          for i in ['1.xml', '2.xml', '3.xml']]
        for path in instance_paths:
            create_instance(self.user.username, open(path), [])

        self.assertEqual(self.xform.instances.count(), 3)
예제 #10
0
 def _contributions_form_submissions(self):
     count = XForm.objects.count()
     path = os.path.join(os.path.dirname(__file__), '..', 'fixtures',
                         'forms', 'contributions')
     form_path = os.path.join(path, 'contributions.xml')
     f = open(form_path)
     xml_file = ContentFile(f.read())
     f.close()
     xml_file.name = 'contributions.xml'
     self.xform = publish_xml_form(xml_file, self.user)
     self.assertTrue(XForm.objects.count() > count)
     instances_path = os.path.join(path, 'instances')
     for uuid in os.listdir(instances_path):
         s_path = os.path.join(instances_path, uuid, 'submission.xml')
         create_instance(self.user.username, open(s_path), [])
     self.assertEqual(self.xform.instances.count(), 6)
예제 #11
0
    def test_get_first_record(self):
        """
        Test get_first_record() function.
        """
        xform_md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | text  | name   | Photo |
        """
        self._create_user_and_login()
        xform = self._publish_markdown(xform_md, self.user)

        self.assertIsNone(get_first_record(Instance.objects.all().only('id')))

        xml_string = """
        <data id="{}">
            <name>Alice</name>
        </data>
        """.format(xform.id_string)
        instance = create_instance(self.user.username,
                                   BytesIO(xml_string.strip().encode('utf-8')),
                                   media_files=[])
        record = get_first_record(Instance.objects.all().only('id'))
        self.assertIsNotNone(record)
        self.assertEqual(record.id, instance.id)
예제 #12
0
def import_instance(username, xform_path, photos, osm_files, status,
                    raise_exception):
    """
    This callback is passed an instance of a XFormInstanceFS.
    See xform_fs.py for more info.
    """
    with django_file(xform_path, field_name="xml_file",
                     content_type="text/xml") as xml_file:
        images = [django_file(jpg, field_name="image",
                  content_type="image/jpeg") for jpg in photos]
        images += [
            django_file(osm, field_name='image',
                        content_type='text/xml')
            for osm in osm_files
        ]
        try:
            instance = create_instance(username, xml_file, images, status)
        except Exception as e:
            if raise_exception:
                raise e

        for i in images:
            i.close()

        if instance:
            return 1
        else:
            return 0
예제 #13
0
def import_instance(username, xform_path, photos, osm_files, status,
                    raise_exception):
    """
    This callback is passed an instance of a XFormInstanceFS.
    See xform_fs.py for more info.
    """
    with django_file(xform_path,
                     field_name="xml_file",
                     content_type="text/xml") as xml_file:
        images = [
            django_file(jpg, field_name="image", content_type="image/jpeg")
            for jpg in photos
        ]
        images += [
            django_file(osm, field_name='image', content_type='text/xml')
            for osm in osm_files
        ]
        try:
            instance = create_instance(username, xml_file, images, status)
        except Exception as e:
            if raise_exception:
                raise e

        for i in images:
            i.close()

        if instance:
            return 1
        else:
            return 0
예제 #14
0
 def _contributions_form_submissions(self):
     count = XForm.objects.count()
     path = os.path.join(os.path.dirname(__file__), '..', 'fixtures',
                         'forms', 'contributions')
     form_path = os.path.join(path, 'contributions.xml')
     with open(form_path, encoding='utf-8') as f:
         xml_file = ContentFile(f.read())
     xml_file.name = 'contributions.xml'
     project = get_user_default_project(self.user)
     self.xform = publish_xml_form(xml_file, self.user, project)
     self.assertTrue(XForm.objects.count() > count)
     instances_path = os.path.join(path, 'instances')
     for uuid in os.listdir(instances_path):
         s_path = os.path.join(instances_path, uuid, 'submission.xml')
         create_instance(self.user.username, open(s_path, 'rb'), [])
     self.assertEqual(self.xform.instances.count(), 6)
예제 #15
0
 def _contributions_form_submissions(self):
     count = XForm.objects.count()
     path = os.path.join(os.path.dirname(__file__),
                         '..', 'fixtures', 'forms', 'contributions')
     form_path = os.path.join(path, 'contributions.xml')
     f = open(form_path)
     xml_file = ContentFile(f.read())
     f.close()
     xml_file.name = 'contributions.xml'
     self.xform = publish_xml_form(xml_file, self.user)
     self.assertTrue(XForm.objects.count() > count)
     instances_path = os.path.join(path, 'instances')
     for uuid in os.listdir(instances_path):
         s_path = os.path.join(instances_path, uuid, 'submission.xml')
         create_instance(self.user.username, open(s_path), [])
     self.assertEqual(self.xform.instances.count(), 6)
예제 #16
0
    def callback(xform_fs):
        """
        This callback is passed an instance of a XFormInstanceFS.
        See xform_fs.py for more info.
        """
        with django_file(xform_fs.path,
                         field_name="xml_file",
                         content_type="text/xml") as xml_file:
            images = [
                django_file(jpg, field_name="image", content_type="image/jpeg")
                for jpg in xform_fs.photos
            ]
            # TODO: if an instance has been submitted make sure all the
            # files are in the database.
            # there shouldn't be any instances with a submitted status in the
            # import.
            instance = create_instance(user.username, xml_file, images, status)

            for i in images:
                i.close()

            if instance:
                return 1
            else:
                return 0
예제 #17
0
def generate_instance(username, xml_file, media_files, uuid=None):
    ''' Process an XForm submission as if done via HTTP

        :param IO xml_file: file-like object containing XML XForm
        :param string username: username of the Form's owner
        :param list media_files: a list of UploadedFile objects
        :param string uuid: an optionnal uuid for the instance.

        :returns a (status, message) tuple. '''

    try:
        instance = create_instance(
            username,
            xml_file,
            media_files,
            uuid=uuid
        )
    except InstanceInvalidUserError:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Username or ID required.")}
    except InstanceEmptyError:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Received empty submission. "
                          u"No instance was created")}
    except FormInactiveError:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Form is not active")}
    except XForm.DoesNotExist:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Form does not exist on this account")}
    except ExpatError:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Improperly formatted XML.")}
    except DuplicateInstance:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Duplicate submission")}

    if instance is None:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Unable to create submission.")}

    user = User.objects.get(username=username)

    audit = {
        "xform": instance.xform.id_string
    }
    audit_log(Actions.SUBMISSION_CREATED,
              user, instance.xform.user,
              _("Created submission on form %(id_string)s.") %
              {"id_string": instance.xform.id_string}, audit, HttpRequest())

    xml_file.close()
    if len(media_files):
        [_file.close() for _file in media_files]

    return {'code': SMS_SUBMISSION_ACCEPTED,
            'text': _(u"[SUCCESS] Your submission has been accepted."),
            'id': get_sms_instance_id(instance)}
예제 #18
0
def generate_instance(username, xml_file, media_files, uuid=None):
    ''' Process an XForm submission as if done via HTTP

        :param IO xml_file: file-like object containing XML XForm
        :param string username: username of the Form's owner
        :param list media_files: a list of UploadedFile objects
        :param string uuid: an optionnal uuid for the instance.

        :returns a (status, message) tuple. '''

    try:
        instance = create_instance(
            username,
            xml_file,
            media_files,
            uuid=uuid
        )
    except InstanceInvalidUserError:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Username or ID required.")}
    except InstanceEmptyError:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Received empty submission. "
                          u"No instance was created")}
    except FormInactiveError:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Form is not active")}
    except XForm.DoesNotExist:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Form does not exist on this account")}
    except ExpatError:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Improperly formatted XML.")}
    except DuplicateInstance:
        return {'code': SMS_SUBMISSION_REFUSED,
                'text': _(u"Duplicate submission")}

    if instance is None:
        return {'code': SMS_INTERNAL_ERROR,
                'text': _(u"Unable to create submission.")}

    user = User.objects.get(username=username)

    audit = {
        "xform": instance.xform.id_string
    }
    audit_log(Actions.SUBMISSION_CREATED,
              user, instance.xform.user,
              _("Created submission on form %(id_string)s.") %
              {"id_string": instance.xform.id_string}, audit, HttpRequest())

    xml_file.close()
    if len(media_files):
        [_file.close() for _file in media_files]

    return {'code': SMS_SUBMISSION_ACCEPTED,
            'text': _(u"[SUCCESS] Your submission has been accepted."),
            'id': get_sms_instance_id(instance)}
예제 #19
0
    def test_numeric_types_are_rendered_as_required(self):
        tutorial_folder = os.path.join(os.path.dirname(__file__), '..',
                                       'fixtures', 'forms', 'tutorial')
        self._publish_xls_file_and_set_xform(
            os.path.join(tutorial_folder, 'tutorial.xls'))

        instance_path = os.path.join(tutorial_folder, 'instances', '1.xml')
        create_instance(self.user.username, open(instance_path), [])

        self.assertEqual(self.xform.instances.count(), 1)
        view = DataViewSet.as_view({'get': 'list'})
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.xform.id)
        self.assertEqual(response.status_code, 200)
        # check that ONLY values with numeric and decimal types are converted
        self.assertEqual(response.data[0].get('age'), 35)
        self.assertEqual(response.data[0].get('net_worth'), 100000.00)
        self.assertEqual(response.data[0].get('imei'), u'351746052009472')
예제 #20
0
    def test_numeric_types_are_rendered_as_required(self):
        tutorial_folder = os.path.join(
            os.path.dirname(__file__),
            '..', 'fixtures', 'forms', 'tutorial')
        self._publish_xls_file_and_set_xform(os.path.join(tutorial_folder,
                                                          'tutorial.xls'))

        instance_path = os.path.join(tutorial_folder, 'instances', '1.xml')
        create_instance(self.user.username, open(instance_path), [])

        self.assertEqual(self.xform.instances.count(), 1)
        view = DataViewSet.as_view({'get': 'list'})
        request = self.factory.get('/', **self.extra)
        response = view(request, pk=self.xform.id)
        self.assertEqual(response.status_code, 200)
        # check that ONLY values with numeric and decimal types are converted
        self.assertEqual(response.data[0].get('age'), 35)
        self.assertEqual(response.data[0].get('net_worth'), 100000.00)
        self.assertEqual(response.data[0].get('imei'), u'351746052009472')
예제 #21
0
 def _upload_instance(self, xml_file, instance_dir_path, files):
     xml_doc = clean_and_parse_xml(xml_file.read())
     xml = StringIO()
     de_node = xml_doc.documentElement
     for node in de_node.firstChild.childNodes:
         xml.write(node.toxml())
     new_xml_file = ContentFile(xml.getvalue())
     new_xml_file.content_type = "text/xml"
     xml.close()
     attachments = []
     for attach in de_node.getElementsByTagName("mediaFile"):
         filename_node = attach.getElementsByTagName("filename")
         filename = filename_node[0].childNodes[0].nodeValue
         if filename in files:
             file_obj = default_storage.open(os.path.join(instance_dir_path, filename))
             mimetype, encoding = mimetypes.guess_type(file_obj.name)
             media_obj = django_file(file_obj, "media_files[]", mimetype)
             attachments.append(media_obj)
     create_instance(self.user.username, new_xml_file, attachments)
    def test_recovers_wrongly_deleted_attachments(self):
        """
        Test that the command recovers the correct
        attachment
        """
        md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | file  | file   | File  |
        |        | image | image  | Image |
        """  # pylint: disable=invalid-name
        self._create_user_and_login()
        xform = self._publish_markdown(md, self.user)

        xml_string = f"""
        <data id="{xform.id_string}">
            <meta>
                <instanceID>uuid:UJ5jz4EszdgH8uhy8nss1AsKaqBPO5VN7</instanceID>
            </meta>
            <file>Health_2011_03_13.xml_2011-03-15_20-30-28.xml</file>
            <image>1300221157303.jpg</image>
        </data>
        """
        media_root = (f'{settings.PROJECT_ROOT}/apps/logger/tests/Health'
                      '_2011_03_13.xml_2011-03-15_20-30-28/')
        image_media = django_file(
            path=f'{media_root}1300221157303.jpg', field_name='image',
            content_type='image/jpeg')
        file_media = django_file(
            path=f'{media_root}Health_2011_03_13.xml_2011-03-15_20-30-28.xml',
            field_name='file', content_type='text/xml')
        instance = create_instance(
            self.user.username,
            BytesIO(xml_string.strip().encode('utf-8')),
            media_files=[file_media, image_media])
        self.assertEqual(
            instance.attachments.filter(deleted_at__isnull=True).count(), 2)
        attachment = instance.attachments.first()

        # Soft delete attachment
        attachment.deleted_at = datetime.now()
        attachment.deleted_by = self.user
        attachment.save()

        self.assertEqual(
            instance.attachments.filter(deleted_at__isnull=True).count(), 1)

        # Attempt recovery of attachment
        recover_deleted_attachments(form_id=instance.xform.id)

        self.assertEqual(
            instance.attachments.filter(deleted_at__isnull=True).count(), 2)
        attachment.refresh_from_db()
        self.assertIsNone(attachment.deleted_at)
        self.assertIsNone(attachment.deleted_by)
예제 #23
0
 def _upload_instance(self, xml_file, instance_dir_path, files):
     xml_doc = clean_and_parse_xml(xml_file.read())
     xml = StringIO()
     de_node = xml_doc.documentElement
     for node in de_node.firstChild.childNodes:
         xml.write(node.toxml())
     new_xml_file = ContentFile(xml.getvalue())
     new_xml_file.content_type = 'text/xml'
     xml.close()
     attachments = []
     for attach in de_node.getElementsByTagName('mediaFile'):
         filename_node = attach.getElementsByTagName('filename')
         filename = filename_node[0].childNodes[0].nodeValue
         if filename in files:
             file_obj = default_storage.open(
                 os.path.join(instance_dir_path, filename))
             mimetype, encoding = mimetypes.guess_type(file_obj.name)
             media_obj = django_file(file_obj, 'media_files[]', mimetype)
             attachments.append(media_obj)
     create_instance(self.user.username, new_xml_file, attachments)
예제 #24
0
    def test_attachment_file_name_validation(self):
        """
        Test that a clear exception is raised when an attachement
        is received whose file name exceeds 100 chars
        """
        md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | image | image1 | Photo |
        |        | image | image2 | Photo |
        """
        self._create_user_and_login()
        self.xform = self._publish_markdown(md, self.user)

        xml_string = """
        <data id="{}">
            <meta>
                <instanceID>uuid:UJ5jSMAJ1Jz4EszdgHy8n851AsKaqBPO5</instanceID>
            </meta>
            <image1>1300221157303.jpg</image1>
            <image2>1300375832136.jpg</image2>
        </data>
        """.format(self.xform.id_string)

        file_path = "{}/apps/logger/tests/Health_2011_03_13."\
                    "xml_2011-03-15_20-30-28/1300221157303"\
                    ".jpg".format(settings.PROJECT_ROOT)
        f = open(file_path, 'rb')
        media_file = InMemoryUploadedFile(
            file=f,
            field_name="image1",
            name=f'{f.name} +\
            test_file_name_test_file_name_test_file_name_test_file_name_test_file_name_test_file_name',  # noqa
            content_type="image/jpeg",
            size=os.path.getsize(file_path),
            charset=None)
        with self.assertRaises(AttachmentNameError):
            create_instance(self.user.username,
                            BytesIO(xml_string.strip().encode('utf-8')),
                            media_files=[media_file])
예제 #25
0
def restore_backup_from_path(dir_path, username, status):
    """
    Only restores xml submissions, media files are assumed to still be in
    storage and will be retrieved by the filename stored within the submission
    """
    num_instances = 0
    num_restored = 0
    for dir_path, dir_names, file_names in os.walk(dir_path):
        for file_name in file_names:
            # check if its a valid xml instance
            xml_instance_path = os.path.join(dir_path, file_name)
            num_instances += 1
            xml_file = django_file(
                xml_instance_path,
                field_name="xml_file",
                content_type="text/xml")
            media_files = []
            date_created = None
            try:
                date_created = _date_created_from_filename(file_name)
            except ValueError as e:
                sys.stderr.write(
                    "Couldn't determine date created from filename: '%s'\n" %
                    file_name)
            else:
                sys.stdout.write("Creating instance from '%s'\n" % file_name)
                try:
                    create_instance(
                        username, xml_file, media_files,
                        date_created_override=date_created)
                    num_restored += 1
                except Exception as e:
                    sys.stderr.write(
                        "Could not restore %s, create instance said: %s\n" %
                        (file_name, e))
    return num_instances, num_restored
예제 #26
0
    def callback(xform_fs):
        """
        This callback is passed an instance of a XFormInstanceFS.
        See xform_fs.py for more info.
        """
        with django_file(xform_fs.path, field_name="xml_file",
                         content_type="text/xml") as xml_file:
            images = [django_file(jpg, field_name="image",
                      content_type="image/jpeg") for jpg in xform_fs.photos]
            # TODO: if an instance has been submitted make sure all the
            # files are in the database.
            # there shouldn't be any instances with a submitted status in the
            # import.
            instance = create_instance(user.username, xml_file, images, status)

            for i in images:
                i.close()

            if instance:
                return 1
            else:
                return 0
예제 #27
0
 def _submit_simple_yes(self):
     create_instance(
         self.user.username,
         TempFileProxy(
             '<?xml version=\'1.0\' ?><yes_or_no id="yes_or_no"><yesno>Yes<'
             '/yesno></yes_or_no>'), [])
예제 #28
0
    def test_replaced_attachments_not_tracked(self):
        """
        Test that when a submission with an attachments is made,
        and later edited, whereby the attachment is replaced,
        the replaced attachment is no longer tracked for that
        submission
        """
        md = """
        | survey |       |        |       |
        |        | type  | name   | label |
        |        | file  | file   | File  |
        |        | image | image  | Image |
        """
        self._create_user_and_login()
        self.xform = self._publish_markdown(md, self.user)

        xml_string = """
        <data id="{}">
            <meta>
                <instanceID>uuid:UJ5jz4EszdgH8uhy8nss1AsKaqBPO5VN7</instanceID>
            </meta>
            <file>Health_2011_03_13.xml_2011-03-15_20-30-28.xml</file>
            <image>1300221157303.jpg</image>
        </data>
        """.format(self.xform.id_string)
        media_root = (f'{settings.PROJECT_ROOT}/apps/logger/tests/Health'
                      '_2011_03_13.xml_2011-03-15_20-30-28/')
        image_media = django_file(path=f'{media_root}1300221157303.jpg',
                                  field_name='image',
                                  content_type='image/jpeg')
        file_media = django_file(
            path=f'{media_root}Health_2011_03_13.xml_2011-03-15_20-30-28.xml',
            field_name='file',
            content_type='text/xml')
        instance = create_instance(self.user.username,
                                   BytesIO(xml_string.strip().encode('utf-8')),
                                   media_files=[file_media, image_media])
        self.assertTrue(instance.json[MEDIA_ALL_RECEIVED])
        self.assertEqual(
            instance.attachments.filter(deleted_at__isnull=True).count(), 2)
        self.assertEquals(instance.json[TOTAL_MEDIA], 2)
        self.assertEquals(instance.json[MEDIA_COUNT], 2)
        self.assertEquals(instance.json[TOTAL_MEDIA], instance.total_media)
        self.assertEquals(instance.json[MEDIA_COUNT], instance.media_count)
        self.assertEquals(instance.json[MEDIA_ALL_RECEIVED],
                          instance.media_all_received)
        patch_value = 'onadata.apps.logger.models.Instance.get_expected_media'
        with patch(patch_value) as get_expected_media:
            get_expected_media.return_value = ['1300375832136.jpg']
            updated_xml_string = """
            <data id="{}">
                <meta>
                    <instanceID>uuid:UJ5jz4EszdgH8uhy8nss1AsKaqBPO5VN7</instanceID>
                </meta>
                <images>
                    <image1>1300375832136.jpg</image1>
                </images>
            </data>
            """.format(self.xform.id_string)
            file2_path = "{}/apps/logger/tests/Water_2011_03_17_2011"\
                "-03-17_16-29-59/1300375832136.jpg".format(
                    settings.PROJECT_ROOT)
            media2_file = django_file(path=file2_path,
                                      field_name="image1",
                                      content_type="image/jpeg")
            create_instance(self.user.username,
                            BytesIO(
                                updated_xml_string.strip().encode('utf-8')),
                            media_files=[media2_file])

            instance2 = Instance.objects.get(pk=instance.pk)
            self.assertTrue(instance2.json[MEDIA_ALL_RECEIVED])
            # Test that only one attachment is recognised for this submission
            # Since the file is no longer present in the submission
            self.assertEquals(instance2.json[TOTAL_MEDIA], 1)
            self.assertEquals(instance2.json[MEDIA_COUNT], 1)
            self.assertEquals(instance2.json[TOTAL_MEDIA],
                              instance2.total_media)
            self.assertEquals(instance2.json[MEDIA_COUNT],
                              instance2.media_count)
            self.assertEquals(instance2.json[MEDIA_ALL_RECEIVED],
                              instance2.media_all_received)
예제 #29
0
파일: views.py 프로젝트: cagulas/onadata
def submission(request, username=None):
    if username and username.lower() != 'crowdforms':
        formlist_user = get_object_or_404(User, username=username.lower())
        profile, created = \
            UserProfile.objects.get_or_create(user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        if username:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/%s/submission' % username)
        else:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/submission')
        return response
    context = RequestContext(request)
    xml_file_list = []
    media_files = []

    # request.FILES is a django.utils.datastructures.MultiValueDict
    # for each key we have a list of values
    try:
        xml_file_list = request.FILES.pop("xml_submission_file", [])
        if len(xml_file_list) != 1:
            return OpenRosaResponseBadRequest(
                _(u"There should be a single XML submission file.")
            )
        # save this XML file and media files as attachments
        media_files = request.FILES.values()

        # get uuid from post request
        uuid = request.POST.get('uuid')

        try:
            instance = create_instance(
                username, xml_file_list[0], media_files,
                uuid=uuid, request=request
            )
        except InstanceInvalidUserError:
            return OpenRosaResponseBadRequest(_(u"Username or ID required."))
        except IsNotCrowdformError:
            return OpenRosaResponseNotAllowed(
                _(u"Sorry but the crowd form you submitted to is closed.")
            )
        except InstanceEmptyError:
            return OpenRosaResponseBadRequest(
                _(u"Received empty submission. No instance was created")
            )
        except FormInactiveError:
            return OpenRosaResponseNotAllowed(_(u"Form is not active"))
        except XForm.DoesNotExist:
            return OpenRosaResponseNotFound(
                _(u"Form does not exist on this account")
            )
        except ExpatError:
            return OpenRosaResponseBadRequest(_(u"Improperly formatted XML."))
        except DuplicateInstance:
            response = OpenRosaResponse(_(u"Duplicate submission"))
            response.status_code = 202
            response['Location'] = request.build_absolute_uri(request.path)
            return response
        except PermissionDenied, e:
            return OpenRosaResponseNotAllowed(e.message)

        if instance is None:
            return OpenRosaResponseBadRequest(
                _(u"Unable to create submission."))

        audit = {
            "xform": instance.xform.id_string
        }
        audit_log(
            Actions.SUBMISSION_CREATED, request.user, instance.xform.user,
            _("Created submission on form %(id_string)s.") %
            {
                "id_string": instance.xform.id_string
            }, audit, request)

        # response as html if posting with a UUID
        if not username and uuid:
            response = _html_submission_response(context, instance)
        else:
            response = _submission_response(context, instance)

        # ODK needs two things for a form to be considered successful
        # 1) the status code needs to be 201 (created)
        # 2) The location header needs to be set to the host it posted to
        response.status_code = 201
        response['Location'] = request.build_absolute_uri(request.path)
        return response
예제 #30
0
def submission(request, username=None):
    if username and username.lower() != 'crowdforms':
        formlist_user = get_object_or_404(User, username=username.lower())
        profile, created = \
            UserProfile.objects.get_or_create(user=formlist_user)

        if profile.require_auth:
            authenticator = HttpDigestAuthenticator()
            if not authenticator.authenticate(request):
                return authenticator.build_challenge_response()
    if request.method == 'HEAD':
        response = OpenRosaResponse(status=204)
        if username:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/%s/submission' % username)
        else:
            response['Location'] = request.build_absolute_uri().replace(
                request.get_full_path(), '/submission')
        return response
    context = RequestContext(request)
    xml_file_list = []
    media_files = []

    # request.FILES is a django.utils.datastructures.MultiValueDict
    # for each key we have a list of values
    try:
        xml_file_list = request.FILES.pop("xml_submission_file", [])
        if len(xml_file_list) != 1:
            return OpenRosaResponseBadRequest(
                _(u"There should be a single XML submission file."))
        # save this XML file and media files as attachments
        media_files = request.FILES.values()

        # get uuid from post request
        uuid = request.POST.get('uuid')

        try:
            instance = create_instance(username,
                                       xml_file_list[0],
                                       media_files,
                                       uuid=uuid,
                                       request=request)
        except InstanceInvalidUserError:
            return OpenRosaResponseBadRequest(_(u"Username or ID required."))
        except IsNotCrowdformError:
            return OpenRosaResponseNotAllowed(
                _(u"Sorry but the crowd form you submitted to is closed."))
        except InstanceEmptyError:
            return OpenRosaResponseBadRequest(
                _(u"Received empty submission. No instance was created"))
        except FormInactiveError:
            return OpenRosaResponseNotAllowed(_(u"Form is not active"))
        except XForm.DoesNotExist:
            return OpenRosaResponseNotFound(
                _(u"Form does not exist on this account"))
        except ExpatError:
            return OpenRosaResponseBadRequest(_(u"Improperly formatted XML."))
        except DuplicateInstance:
            response = OpenRosaResponse(_(u"Duplicate submission"))
            response.status_code = 202
            response['Location'] = request.build_absolute_uri(request.path)
            return response
        except PermissionDenied, e:
            return OpenRosaResponseNotAllowed(e.message)

        if instance is None:
            return OpenRosaResponseBadRequest(
                _(u"Unable to create submission."))

        audit = {"xform": instance.xform.id_string}
        audit_log(
            Actions.SUBMISSION_CREATED, request.user, instance.xform.user,
            _("Created submission on form %(id_string)s.") %
            {"id_string": instance.xform.id_string}, audit, request)

        # response as html if posting with a UUID
        if not username and uuid:
            response = _html_submission_response(context, instance)
        else:
            response = _submission_response(context, instance)

        # ODK needs two things for a form to be considered successful
        # 1) the status code needs to be 201 (created)
        # 2) The location header needs to be set to the host it posted to
        response.status_code = 201
        response['Location'] = request.build_absolute_uri(request.path)
        return response
예제 #31
0
 def _submit_simple_yes(self):
     create_instance(self.user.username, TempFileProxy(
         '<?xml version=\'1.0\' ?><yes_or_no id="yes_or_no"><yesno>Yes<'
         '/yesno></yes_or_no>'), [])
예제 #32
0
 def submit_simple_yes():
     create_instance(self.user.username, TempFileProxy("""
         <?xml version='1.0' ?><yes_or_no id="yes_or_no"><yesno>Yes</yesno></yes_or_no>
         """.strip()), [])