예제 #1
0
    def setUp(self):
        self.user = User.objects.create(username="******",
                                        email="*****@*****.**")
        self.project = UserProfile.objects.create(user=self.user)
        self.user.set_password("pass")
        self.project = get_user_default_project(self.user)
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.project = self.project
        self.xform1.json = '{"id_string": "yes_or_no_form", "children": '\
                           '[{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.project = self.project
        self.xform2.json = '{"id_string": "start_time_form", "children": '\
                           '[{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime_form", "title": "start_time_form",'\
                           '"type": "survey"}'\
                           .strip()

        self._get_xml_for_form(self.xform1)
        self._get_xml_for_form(self.xform2)
예제 #2
0
    def setUp(self):
        self.user = User.objects.create(username="******",
                                        email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        def get_xml_for_form(xform):
            builder = SurveyElementBuilder()
            sss = builder.create_survey_element_from_json(xform.json)
            xform.xml = sss.to_xml()
            xform._mark_start_time_boolean()
            xform.save()

        get_xml_for_form(self.xform1)
        get_xml_for_form(self.xform2)
예제 #3
0
def publish_xml_form(xml_file, user, project, id_string=None, created_by=None):
    xml = xml_file.read()
    if isinstance(xml, bytes):
        xml = xml.decode('utf-8')
    survey = create_survey_element_from_xml(xml)
    form_json = survey.to_json()
    if id_string:
        dd = DataDictionary.objects.get(user=user,
                                        id_string=id_string,
                                        project=project)
        dd.xml = xml
        dd.json = form_json
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml()
        dd._set_hash()
        dd.save()

        return dd
    else:
        created_by = created_by or user
        dd = DataDictionary(created_by=created_by,
                            user=user,
                            xml=xml,
                            json=form_json,
                            project=project)
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml(file_name=xml_file.name)
        dd._set_hash()
        dd.save()

        return dd
예제 #4
0
def publish_xml_form(xml_file, user, project, id_string=None, created_by=None):
    xml = xml_file.read()
    if isinstance(xml, bytes):
        xml = xml.decode('utf-8')
    survey = create_survey_element_from_xml(xml)
    form_json = survey.to_json()
    if id_string:
        dd = DataDictionary.objects.get(
            user=user, id_string=id_string, project=project)
        dd.xml = xml
        dd.json = form_json
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml()
        dd._set_hash()
        dd.save()

        return dd
    else:
        created_by = created_by or user
        dd = DataDictionary(
            created_by=created_by,
            user=user,
            xml=xml,
            json=form_json,
            project=project)
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml(file_name=xml_file.name)
        dd._set_hash()
        dd.save()

        return dd
예제 #5
0
    def setUp(self):
        self.user = User.objects.create(
            username="******", email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        def get_xml_for_form(xform):
            builder = SurveyElementBuilder()
            sss = builder.create_survey_element_from_json(xform.json)
            xform.xml = sss.to_xml()
            xform._mark_start_time_boolean()
            xform.save()
        get_xml_for_form(self.xform1)
        get_xml_for_form(self.xform2)
예제 #6
0
def publish_xml_form(xml_file, user, id_string=None):
    xml = xml_file.read()
    survey = create_survey_element_from_xml(xml)
    form_json = survey.to_json()
    if id_string:
        dd = DataDictionary.objects.get(user=user, id_string=id_string)
        dd.xml = xml
        dd.json = form_json
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml()
        dd.save()
        return dd
    else:
        dd = DataDictionary(user=user, xml=xml, json=form_json)
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml(file_name=xml_file.name)
        dd.save()
        return dd
예제 #7
0
    def setUp(self):
        self.user = User.objects.create(
            username="******", email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        self._get_xml_for_form(self.xform1)
        self._get_xml_for_form(self.xform2)
예제 #8
0
 def _split_gps_fields(cls, record, gps_fields):
     updated_gps_fields = {}
     for key, value in record.iteritems():
         if key in gps_fields and isinstance(value, basestring):
             gps_xpaths = DataDictionary.get_additional_geopoint_xpaths(key)
             gps_parts = dict([(xpath, None) for xpath in gps_xpaths])
             # hack, check if its a list and grab the object within that
             parts = value.split(' ')
             # TODO: check whether or not we can have a gps recording
             # from ODKCollect that has less than four components,
             # for now we are assuming that this is not the case.
             if len(parts) == 4:
                 gps_parts = dict(zip(gps_xpaths, parts))
             updated_gps_fields.update(gps_parts)
         # check for repeats within record i.e. in value
         elif type(value) == list:
             for list_item in value:
                 if type(list_item) == dict:
                     cls._split_gps_fields(list_item, gps_fields)
     record.update(updated_gps_fields)
예제 #9
0
 def _split_gps_fields(cls, record, gps_fields):
     updated_gps_fields = {}
     for key, value in record.iteritems():
         if key in gps_fields and isinstance(value, basestring):
             gps_xpaths = DataDictionary.get_additional_geopoint_xpaths(key)
             gps_parts = dict([(xpath, None) for xpath in gps_xpaths])
             # hack, check if its a list and grab the object within that
             parts = value.split(' ')
             # TODO: check whether or not we can have a gps recording
             # from ODKCollect that has less than four components,
             # for now we are assuming that this is not the case.
             if len(parts) == 4:
                 gps_parts = dict(zip(gps_xpaths, parts))
             updated_gps_fields.update(gps_parts)
         # check for repeats within record i.e. in value
         elif type(value) == list:
             for list_item in value:
                 if type(list_item) == dict:
                     cls._split_gps_fields(list_item, gps_fields)
     record.update(updated_gps_fields)
예제 #10
0
def publish_xml_form(xml_file, user, id_string=None):
    xml = xml_file.read()
    survey = create_survey_element_from_xml(xml)
    form_json = survey.to_json()
    if id_string:
        dd = DataDictionary.objects.get(user=user, id_string=id_string)
        dd.xml = xml
        dd.json = form_json
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml()
        dd.save()
        return dd
    else:
        dd = DataDictionary(user=user, xml=xml, json=form_json)
        dd._mark_start_time_boolean()
        set_uuid(dd)
        dd._set_uuid_in_xml(file_name=xml_file.name)
        dd.save()
        return dd
예제 #11
0
def get_data_dictionary_from_survey(survey):
    dd = DataDictionary()
    dd._survey = survey

    return dd
예제 #12
0
        def build_sections(current_section,
                           survey_element,
                           sections,
                           select_multiples,
                           gps_fields,
                           encoded_fields,
                           field_delimiter='/',
                           remove_group_name=False):

            for child in survey_element.children:
                current_section_name = current_section['name']
                # if a section, recurs
                if isinstance(child, Section):
                    # if its repeating, build a new section
                    if isinstance(child, RepeatingSection):
                        # section_name in recursive call changes
                        section = {
                            'name': child.get_abbreviated_xpath(),
                            'elements': []
                        }
                        self.sections.append(section)
                        build_sections(section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, field_delimiter,
                                       remove_group_name)
                    else:
                        # its a group, recurs using the same section
                        build_sections(current_section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, field_delimiter,
                                       remove_group_name)
                elif isinstance(child, Question) and child.bind.get(u"type")\
                        not in QUESTION_TYPES_TO_EXCLUDE:
                    # add to survey_sections
                    if isinstance(child, Question):
                        child_xpath = child.get_abbreviated_xpath()
                        _title = ExportBuilder.format_field_title(
                            child.get_abbreviated_xpath(), field_delimiter, dd,
                            remove_group_name)
                        _label = \
                            dd.get_label(child_xpath, elem=child) or _title
                        current_section['elements'].append({
                            'label':
                            _label,
                            'title':
                            _title,
                            'xpath':
                            child_xpath,
                            'type':
                            child.bind.get(u"type")
                        })

                        if _is_invalid_for_mongo(child_xpath):
                            if current_section_name not in encoded_fields:
                                encoded_fields[current_section_name] = {}
                            encoded_fields[current_section_name].update(
                                {child_xpath: _encode_for_mongo(child_xpath)})

                    # if its a select multiple, make columns out of its choices
                    if child.bind.get(u"type") == MULTIPLE_SELECT_BIND_TYPE\
                            and self.SPLIT_SELECT_MULTIPLES:
                        choices = self._get_select_mulitples_choices(
                            child, dd, field_delimiter, remove_group_name)
                        for choice in choices:
                            if choice not in current_section['elements']:
                                current_section['elements'].append(choice)

                        choices_xpaths = [c['xpath'] for c in choices]
                        _append_xpaths_to_section(
                            current_section_name, select_multiples,
                            child.get_abbreviated_xpath(), choices_xpaths)

                    # split gps fields within this section
                    if child.bind.get(u"type") == GEOPOINT_BIND_TYPE:
                        # add columns for geopoint components
                        xpaths = DataDictionary.get_additional_geopoint_xpaths(
                            child.get_abbreviated_xpath())
                        for xpath in xpaths:
                            _title = ExportBuilder.format_field_title(
                                xpath, field_delimiter, dd, remove_group_name)
                            current_section['elements'].append({
                                'label':
                                _title,
                                'title':
                                _title,
                                'xpath':
                                xpath,
                                'type':
                                'decimal'
                            })
                        _append_xpaths_to_section(
                            current_section_name, gps_fields,
                            child.get_abbreviated_xpath(), xpaths)
예제 #13
0
def process_tableau_data(data, xform):
    """
    Streamlines the row header fields
    with the column header fields for the same form.
    Handles Flattenning repeat data for tableau
    """
    def get_xpath(key, nested_key):
        val = nested_key.split('/')
        nested_key_diff = val[len(key.split('/')):]
        xpaths = key + f'[{index}]/' + '/'.join(nested_key_diff)
        return xpaths

    def get_updated_data_dict(key, value, data_dict):
        """
        Generates key, value pairs for select multiple question types.
        Defining the new xpaths from the
        question name(key) and the choice name(value)
        in accordance with how we generate the tableau schema.
        """
        if isinstance(value, str) and data_dict:
            choices = value.split(" ")
            for choice in choices:
                xpaths = f'{key}/{choice}'
                data_dict[xpaths] = choice
        elif isinstance(value, list):
            try:
                for item in value:
                    for (nested_key, nested_val) in item.items():
                        xpath = get_xpath(key, nested_key)
                        data_dict[xpath] = nested_val
            except AttributeError:
                data_dict[key] = value

        return data_dict

    def get_ordered_repeat_value(key, item, index):
        """
        Return Ordered Dict of repeats in the order in which they appear in
        the XForm.
        """
        children = xform.get_child_elements(key, split_select_multiples=False)
        item_list = OrderedDict()
        data = {}

        for elem in children:
            if not question_types_to_exclude(elem.type):
                new_xpath = elem.get_abbreviated_xpath()
                item_list[new_xpath] = item.get(new_xpath, DEFAULT_NA_REP)
                # Loop through repeat data and flatten it
                # given the key "children/details" and nested_key/
                # abbreviated xpath "children/details/immunization/polio_1",
                # generate ["children", index, "immunization/polio_1"]
                for (nested_key, nested_val) in item_list.items():
                    qstn_type = xform.get_element(nested_key).type
                    xpaths = get_xpath(key, nested_key)
                    if qstn_type == MULTIPLE_SELECT_TYPE:
                        data = get_updated_data_dict(xpaths, nested_val, data)
                    elif qstn_type == REPEAT_SELECT_TYPE:
                        data = get_updated_data_dict(xpaths, nested_val, data)
                    else:
                        data[xpaths] = nested_val
        return data

    result = []
    if data:
        headers = xform.get_headers()
        tableau_headers = remove_metadata_fields(headers)
        for row in data:
            diff = set(tableau_headers).difference(set(row))
            flat_dict = dict.fromkeys(diff, None)
            for (key, value) in row.items():
                if isinstance(value, list) and key not in [
                        ATTACHMENTS, NOTES, GEOLOCATION
                ]:
                    for index, item in enumerate(value, start=1):
                        # order repeat according to xform order
                        item = get_ordered_repeat_value(key, item, index)
                        flat_dict.update(item)
                else:
                    try:
                        qstn_type = xform.get_element(key).type
                        if qstn_type == MULTIPLE_SELECT_TYPE:
                            flat_dict = get_updated_data_dict(
                                key, value, flat_dict)
                        if qstn_type == 'geopoint':
                            parts = value.split(' ')
                            gps_xpaths = \
                                DataDictionary.get_additional_geopoint_xpaths(
                                    key)
                            gps_parts = dict([(xpath, None)
                                              for xpath in gps_xpaths])
                            if len(parts) == 4:
                                gps_parts = dict(zip(gps_xpaths, parts))
                                flat_dict.update(gps_parts)
                        else:
                            flat_dict[key] = value
                    except AttributeError:
                        flat_dict[key] = value

            result.append(flat_dict)
    return result
        def build_sections(current_section,
                           survey_element,
                           sections,
                           select_multiples,
                           gps_fields,
                           encoded_fields,
                           select_one,
                           select_label_map,
                           field_delimiter='/'):
            print "survey_element.children"
            print survey_element.children
            print "current_section"
            print current_section
            for child in survey_element.children:
                print "survey_element.child"
                print child
                current_section_name = current_section['name']
                # if a section, recurs
                if isinstance(child, Section):
                    # if its repeating, build a new section
                    if isinstance(child, RepeatingSection):
                        # section_name in recursive call changes
                        section = {
                            'name': child.get_abbreviated_xpath(),
                            'elements': []
                        }
                        self.sections.append(section)
                        build_sections(section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, select_one,
                                       select_label_map, field_delimiter)
                    else:
                        # its a group, recurs using the same section
                        build_sections(current_section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, select_one,
                                       select_label_map, field_delimiter)
                elif isinstance(child, Question) and child.bind.get(u"type")\
                        not in QUESTION_TYPES_TO_EXCLUDE:
                    # add to survey_sections
                    if isinstance(child, Question):
                        # print('child bind type: ' ,child.bind.get(u"type"))
                        if child.bind.get(
                                u"type"
                        ) == SINGLE_SELECT_BIND_TYPE and self.SHOW_LABEL:
                            # print ('get select 1 type question :D ')
                            for c in child.children:
                                _xpath = c.get_abbreviated_xpath()
                                if not self.SHOW_LABEL:
                                    _title = ExportBuilder.format_field_title(
                                        _xpath, field_delimiter)
                                else:
                                    _title = c.label

                                _title_custom = c.label
                                select_label_map[_xpath] = _title_custom
                                # _xpath = c.get_abbreviated_xpath()

                                choice = {
                                    'title': _title,
                                    'xpath': _xpath,
                                    'type': 'string',
                                    'label': _title
                                }
                                # if choice not in current_section['elements']:current_section['elements'].append(choice)
                                _append_xpaths_to_section(
                                    current_section_name, select_one,
                                    child.get_abbreviated_xpath(), [
                                        c.get_abbreviated_xpath()
                                        for c in child.children
                                    ])

                        child_xpath = child.get_abbreviated_xpath()
                        current_section['elements'].append({
                            'title':
                            ExportBuilder.format_field_title(
                                child.get_abbreviated_xpath(),
                                field_delimiter),
                            'xpath':
                            child_xpath,
                            'type':
                            child.bind.get(u"type"),
                            'label':
                            child.label
                        })

                        if _is_invalid_for_mongo(child_xpath):
                            if current_section_name not in encoded_fields:
                                encoded_fields[current_section_name] = {}
                            encoded_fields[current_section_name].update(
                                {child_xpath: _encode_for_mongo(child_xpath)})

                    # if its a select multiple, make columns out of its choices
                    if child.bind.get(u"type") == MULTIPLE_SELECT_BIND_TYPE\
                            and self.SPLIT_SELECT_MULTIPLES:
                        for c in child.children:
                            _xpath = c.get_abbreviated_xpath()
                            _title = ExportBuilder.format_field_title(
                                _xpath, field_delimiter)
                            _title_custom = c.label
                            choice = {
                                'title': _title,
                                'xpath': _xpath,
                                'type': 'string',
                                'label': _title_custom
                            }

                            if self.SHOW_LABEL:
                                select_label_map[_xpath] = _title_custom

                            if choice not in current_section['elements']:
                                current_section['elements'].append(choice)
                        _append_xpaths_to_section(
                            current_section_name, select_multiples,
                            child.get_abbreviated_xpath(), [
                                c.get_abbreviated_xpath()
                                for c in child.children
                            ])

                    # split gps fields within this section
                    if child.bind.get(u"type") == GEOPOINT_BIND_TYPE:
                        # add columns for geopoint components
                        xpaths = DataDictionary.get_additional_geopoint_xpaths(
                            child.get_abbreviated_xpath())
                        current_section['elements'].extend([{
                            'title':
                            ExportBuilder.format_field_title(
                                xpath, field_delimiter),
                            'xpath':
                            xpath,
                            'type':
                            'decimal'
                        } for xpath in xpaths])
                        _append_xpaths_to_section(
                            current_section_name, gps_fields,
                            child.get_abbreviated_xpath(), xpaths)
예제 #15
0
class TestSimpleSubmission(TestCase):
    def _get_xml_for_form(self, xform):
        builder = SurveyElementBuilder()
        sss = builder.create_survey_element_from_json(xform.json)
        xform.xml = sss.to_xml()
        xform._mark_start_time_boolean()
        xform.save()

    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

    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>'), [])

    def setUp(self):
        self.user = User.objects.create(
            username="******", email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        self._get_xml_for_form(self.xform1)
        self._get_xml_for_form(self.xform2)

    def tearDown(self):
        self.xform1.delete()
        self.user.delete()

    def test_start_time_boolean_properly_set(self):
        self.assertFalse(self.xform1.has_start_time)
        self.assertTrue(self.xform2.has_start_time)

    def test_simple_yes_submission(self):
        self.assertEquals(0, self.xform1.instances.count())

        self._submit_simple_yes()

        self.assertEquals(1, self.xform1.instances.count())

        self._submit_simple_yes()

        # a simple "yes" submission *SHOULD* increment the survey count
        self.assertEquals(2, self.xform1.instances.count())

    def test_start_time_submissions(self):
        """This test checks to make sure that instances
        *with start_time available* are marked as duplicates when the XML is a
        direct match.
        """
        self.assertEquals(0, self.xform2.instances.count())
        self._submit_at_hour(11)
        self.assertEquals(1, self.xform2.instances.count())
        self._submit_at_hour(12)
        self.assertEquals(2, self.xform2.instances.count())
        # an instance from 11 AM already exists in the database, so it
        # *SHOULD NOT* increment the survey count.
        self._submit_at_hour(11)
        self.assertEquals(2, self.xform2.instances.count())

    def test_corrupted_submission(self):
        """Test xml submissions that contain unicode characters.
        """
        xml = 'v\xee\xf3\xc0k\x91\x91\xae\xff\xff\xff\xff\xcf[$b\xd0\xc9\'uW\x80RP\xff\xff\xff\xff7\xd0\x03%F\xa7p\xa2\x87\xb6f\xb1\xff\xff\xff\xffg~\xf3O\xf3\x9b\xbc\xf6ej_$\xff\xff\xff\xff\x13\xe8\xa9D\xed\xfb\xe7\xa4d\x96>\xfa\xff\xff\xff\xff\xc7h"\x86\x14\\.\xdb\x8aoF\xa4\xff\xff\xff\xff\xcez\xff\x01\x0c\x9a\x94\x18\xe1\x03\x8e\xfa\xff\xff\xff\xff39P|\xf9n\x18F\xb1\xcb\xacd\xff\xff\xff\xff\xce>\x97i;1u\xcfI*\xf2\x8e\xff\xff\xff\xffFg\x9d\x0fR:\xcd*\x14\x85\xf0e\xff\xff\xff\xff\xd6\xdc\xda\x8eM\x06\xf1\xfc\xc1\xe8\xd6\xe0\xff\xff\xff\xff\xe7G\xe1\xa1l\x02T\n\xde\x1boJ\xff\xff\xff\xffz \x92\xbc\tR{#\xbb\x9f\xa6s\xff\xff\xff\xff\xa2\x8f(\xb6=\xe11\xfcV\xcf\xef\x0b\xff\xff\xff\xff\xa3\x83\x7ft\xd7\x05+)\xeb9\\*\xff\xff\xff\xff\xfe\x93\xb2\xa2\x06n;\x1b4\xaf\xa6\x93\xff\xff\xff\xff\xe7\xf7\x12Q\x83\xbb\x9a\xc8\xc8q34\xff\xff\xff\xffT2\xa5\x07\x9a\xc9\x89\xf8\x14Y\xab\x19\xff\xff\xff\xff\x16\xd0R\x1d\x06B\x95\xea\\\x1ftP\xff\xff\xff\xff\x94^\'\x01#oYV\xc5\\\xb7@\xff\xff\xff\xff !\x11\x00\x8b\xf3[\xde\xa2\x01\x9dl\xff\xff\xff\xff\xe7z\x92\xc3\x03\xd3\xb5B5 \xaa7\xff\xff\xff\xff\xff\xc3Q:\xa6\xb3\xa3\x1e\x90 \xa0\\\xff\xff\xff\xff\xff\x14<\x03Vr\xe8Z.Ql\xf5\xff\xff\xff\xffEx\xf7\x0b_\xa1\x7f\xfcG\xa4\x18\xcd\xff\xff\xff\xff1|~i\x00\xb3. ,1Q\x0e\xff\xff\xff\xff\x87a\x933Y\xd7\xe1B#\xa7a\xee\xff\xff\xff\xff\r\tJ\x18\xd0\xdb\x0b\xbe\x00\x91\x95\x9e\xff\xff\xff\xffHfW\xcd\x8f\xa9z6|\xc5\x171\xff\xff\xff\xff\xf5tP7\x93\x02Q|x\x17\xb1\xcb\xff\xff\xff\xffVb\x11\xa0*\xd9;\x0b\xf8\x1c\xd3c\xff\xff\xff\xff\x84\x82\xcer\x15\x99`5LmA\xd5\xff\xff\xff\xfft\xce\x8e\xcbw\xee\xf3\xc0w\xca\xb3\xfd\xff\xff\xff\xff\xb0\xaab\x92\xd4\x02\x84H3\x94\xa9~\xff\xff\xff\xff\xfe7\x18\xcaW=\x94\xbc|\x0f{\x84\xff\xff\xff\xff\xe8\xdf\xde?\x8b\xb7\x9dH3\xc1\xf2\xaa\xff\xff\xff\xff\xbe\x00\xba\xd7\xba6!\x95g\xb01\xf9\xff\xff\xff\xff\x93\xe3\x90YH9g\xf7\x97nhv\xff\xff\xff\xff\x82\xc7`\xaebn\x9d\x1e}\xba\x1e/\xff\xff\xff\xff\xbd\xe5\xa1\x05\x03\xf26\xa0\xe2\xc1*\x07\xff\xff\xff\xffny\x88\x9f\x19\xd2\xd0\xf7\x1de\xa7\xe0\xff\xff\xff\xff\xc4O&\x14\x8dVH\x90\x8b+\x03\xf9\xff\xff\xff\xff\xf69\xc2\xabo%\xcc/\xc9\xe4dP\xff\xff\xff\xff (\x08G\xebM\x03\x99Y\xb4\xb3\x1f\xff\xff\xff\xffzH\xd2\x19p#\xc5\xa4)\xfd\x05\x9a\xff\xff\xff\xffd\x86\xb2F\x15\x0f\xf4.\xfd\\\xd4#\xff\xff\xff\xff\xaf\xbe\xc6\x9di\xa0\xbc\xd5>cp\xe2\xff\xff\xff\xff&h\x91\xe9\xa0H\xdd\xaer\x87\x18E\xff\xff\xff\xffjg\x08E\x8f\xa4&\xab\xff\x98\x0ei\xff\xff\xff\xff\x01\xfd{"\xed\\\xa3M\x9e\xc3\xf8K\xff\xff\xff\xff\x87Y\x98T\xf0\xa6\xec\x98\xb3\xef\xa7\xaa\xff\xff\xff\xffA\xced\xfal\xd3\xd9\x06\xc6~\xee}\xff\xff\xff\xff:\x7f\xa2\x10\xc7\xadB,}PF%\xff\xff\xff\xff\xb2\xbc\n\x17%\x98\x904\x89\tF\x1f\xff\xff\xff\xff\xdc\xd8\xc6@#M\x87uf\x02\xc6g\xff\xff\xff\xffK\xaf\xb0-=l\x07\xe1Nv\xe4\xf4\xff\xff\xff\xff\xdb\x13\'Ne\xb2UT\x9a#\xb1^\xff\xff\xff\xff\xb2\rne\xd1\x9d\x88\xda\xbb!\xfa@\xff\xff\xff\xffflq\x0f\x01z]uh\'|?\xff\xff\xff\xff\xd5\'\x19\x865\xba\xf2\xe7\x8fR-\xcc\xff\xff\xff\xff\xce\xd6\xfdi\x04\x9b\xa7\tu\x05\xb7\xc8\xff\xff\xff\xff\xc3\xd0)\x11\xdd\xb1\xa5kp\xc9\xd5\xf7\xff\xff\xff\xff\xffU\x9f \xb7\xa1#3rup[\xff\xff\xff\xff\xfc='  # noqa

        request = RequestFactory().post('/')
        request.user = self.user
        error, instance = safe_create_instance(
            self.user.username, TempFileProxy(xml), None, None, request)
        text = 'File likely corrupted during transmission'
        self.assertContains(error, text, status_code=400)
예제 #16
0
class TestSimpleSubmission(TestCase):
    def setUp(self):
        self.user = User.objects.create(
            username="******", email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        def get_xml_for_form(xform):
            builder = SurveyElementBuilder()
            sss = builder.create_survey_element_from_json(xform.json)
            xform.xml = sss.to_xml()
            xform._mark_start_time_boolean()
            xform.save()
        get_xml_for_form(self.xform1)
        get_xml_for_form(self.xform2)

    def tearDown(self):
        self.xform1.delete()
        self.user.delete()

    def test_start_time_boolean_properly_set(self):
        self.assertFalse(self.xform1.has_start_time)
        self.assertTrue(self.xform2.has_start_time)

    def test_simple_yes_submission(self):
        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()), [])
        self.assertEquals(0, self.xform1.instances.count())
        submit_simple_yes()
        self.assertEquals(1, self.xform1.instances.count())
        # a simple "yes" submission *SHOULD* increment the survey count
        submit_simple_yes()
        self.assertEquals(2, self.xform1.instances.count())

    def test_start_time_submissions(self):
        """
        This test checks to make sure that instances
        *with start_time available* are marked as duplicates when the XML is a
        direct match.
        """
        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
        self.assertEquals(0, self.xform2.instances.count())
        submit_at_hour(11)
        self.assertEquals(1, self.xform2.instances.count())
        submit_at_hour(12)
        self.assertEquals(2, self.xform2.instances.count())
        # an instance from 11 AM already exists in the database, so it
        # *SHOULD NOT* increment the survey count.
        submit_at_hour(11)
        self.assertEquals(2, self.xform2.instances.count())
예제 #17
0
        def build_sections(
                current_section, survey_element, sections, select_multiples,
                gps_fields, encoded_fields, field_delimiter='/'):
            for child in survey_element.children:
                current_section_name = current_section['name']
                # if a section, recurs
                if isinstance(child, Section):
                    # if its repeating, build a new section
                    if isinstance(child, RepeatingSection):
                        # section_name in recursive call changes
                        section = {
                            'name': child.get_abbreviated_xpath(),
                            'elements': []}
                        self.sections.append(section)
                        build_sections(
                            section, child, sections, select_multiples,
                            gps_fields, encoded_fields, field_delimiter)
                    else:
                        # its a group, recurs using the same section
                        build_sections(
                            current_section, child, sections, select_multiples,
                            gps_fields, encoded_fields, field_delimiter)
                elif isinstance(child, Question) and child.bind.get(u"type")\
                        not in QUESTION_TYPES_TO_EXCLUDE:
                    # add to survey_sections
                    if isinstance(child, Question):
                        child_xpath = child.get_abbreviated_xpath()
                        current_section['elements'].append({
                            'title': ExportBuilder.format_field_title(
                                child.get_abbreviated_xpath(),
                                field_delimiter),
                            'xpath': child_xpath,
                            'type': child.bind.get(u"type")
                        })

                        if _is_invalid_for_mongo(child_xpath):
                            if current_section_name not in encoded_fields:
                                encoded_fields[current_section_name] = {}
                            encoded_fields[current_section_name].update(
                                {child_xpath: _encode_for_mongo(child_xpath)})

                    # if its a select multiple, make columns out of its choices
                    if child.bind.get(u"type") == MULTIPLE_SELECT_BIND_TYPE\
                            and self.SPLIT_SELECT_MULTIPLES:
                        for c in child.children:
                            _xpath = c.get_abbreviated_xpath()
                            _title = ExportBuilder.format_field_title(
                                _xpath, field_delimiter)
                            choice = {
                                'title': _title,
                                'xpath': _xpath,
                                'type': 'string'
                            }

                            if choice not in current_section['elements']:
                                current_section['elements'].append(choice)
                        _append_xpaths_to_section(
                            current_section_name, select_multiples,
                            child.get_abbreviated_xpath(),
                            [c.get_abbreviated_xpath()
                             for c in child.children])

                    # split gps fields within this section
                    if child.bind.get(u"type") == GEOPOINT_BIND_TYPE:
                        # add columns for geopoint components
                        xpaths = DataDictionary.get_additional_geopoint_xpaths(
                            child.get_abbreviated_xpath())
                        current_section['elements'].extend(
                            [
                                {
                                    'title': ExportBuilder.format_field_title(
                                        xpath, field_delimiter),
                                    'xpath': xpath,
                                    'type': 'decimal'
                                }
                                for xpath in xpaths
                            ])
                        _append_xpaths_to_section(
                            current_section_name, gps_fields,
                            child.get_abbreviated_xpath(), xpaths)
예제 #18
0
class TestSimpleSubmission(TestCase):
    def _get_xml_for_form(self, xform):
        builder = SurveyElementBuilder()
        sss = builder.create_survey_element_from_json(xform.json)
        xform.xml = sss.to_xml()
        xform._mark_start_time_boolean()
        xform.save()

    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

    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>'), [])

    def setUp(self):
        self.user = User.objects.create(username="******",
                                        email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        self._get_xml_for_form(self.xform1)
        self._get_xml_for_form(self.xform2)

    def tearDown(self):
        self.xform1.delete()
        self.user.delete()

    def test_start_time_boolean_properly_set(self):
        self.assertFalse(self.xform1.has_start_time)
        self.assertTrue(self.xform2.has_start_time)

    def test_simple_yes_submission(self):
        self.assertEquals(0, self.xform1.instances.count())

        self._submit_simple_yes()

        self.assertEquals(1, self.xform1.instances.count())

        self._submit_simple_yes()

        # a simple "yes" submission *SHOULD* increment the survey count
        self.assertEquals(2, self.xform1.instances.count())

    def test_start_time_submissions(self):
        """This test checks to make sure that instances
        *with start_time available* are marked as duplicates when the XML is a
        direct match.
        """
        self.assertEquals(0, self.xform2.instances.count())
        self._submit_at_hour(11)
        self.assertEquals(1, self.xform2.instances.count())
        self._submit_at_hour(12)
        self.assertEquals(2, self.xform2.instances.count())
        # an instance from 11 AM already exists in the database, so it
        # *SHOULD NOT* increment the survey count.
        self._submit_at_hour(11)
        self.assertEquals(2, self.xform2.instances.count())

    def test_corrupted_submission(self):
        """Test xml submissions that contain unicode characters.
        """
        xml = 'v\xee\xf3\xc0k\x91\x91\xae\xff\xff\xff\xff\xcf[$b\xd0\xc9\'uW\x80RP\xff\xff\xff\xff7\xd0\x03%F\xa7p\xa2\x87\xb6f\xb1\xff\xff\xff\xffg~\xf3O\xf3\x9b\xbc\xf6ej_$\xff\xff\xff\xff\x13\xe8\xa9D\xed\xfb\xe7\xa4d\x96>\xfa\xff\xff\xff\xff\xc7h"\x86\x14\\.\xdb\x8aoF\xa4\xff\xff\xff\xff\xcez\xff\x01\x0c\x9a\x94\x18\xe1\x03\x8e\xfa\xff\xff\xff\xff39P|\xf9n\x18F\xb1\xcb\xacd\xff\xff\xff\xff\xce>\x97i;1u\xcfI*\xf2\x8e\xff\xff\xff\xffFg\x9d\x0fR:\xcd*\x14\x85\xf0e\xff\xff\xff\xff\xd6\xdc\xda\x8eM\x06\xf1\xfc\xc1\xe8\xd6\xe0\xff\xff\xff\xff\xe7G\xe1\xa1l\x02T\n\xde\x1boJ\xff\xff\xff\xffz \x92\xbc\tR{#\xbb\x9f\xa6s\xff\xff\xff\xff\xa2\x8f(\xb6=\xe11\xfcV\xcf\xef\x0b\xff\xff\xff\xff\xa3\x83\x7ft\xd7\x05+)\xeb9\\*\xff\xff\xff\xff\xfe\x93\xb2\xa2\x06n;\x1b4\xaf\xa6\x93\xff\xff\xff\xff\xe7\xf7\x12Q\x83\xbb\x9a\xc8\xc8q34\xff\xff\xff\xffT2\xa5\x07\x9a\xc9\x89\xf8\x14Y\xab\x19\xff\xff\xff\xff\x16\xd0R\x1d\x06B\x95\xea\\\x1ftP\xff\xff\xff\xff\x94^\'\x01#oYV\xc5\\\xb7@\xff\xff\xff\xff !\x11\x00\x8b\xf3[\xde\xa2\x01\x9dl\xff\xff\xff\xff\xe7z\x92\xc3\x03\xd3\xb5B5 \xaa7\xff\xff\xff\xff\xff\xc3Q:\xa6\xb3\xa3\x1e\x90 \xa0\\\xff\xff\xff\xff\xff\x14<\x03Vr\xe8Z.Ql\xf5\xff\xff\xff\xffEx\xf7\x0b_\xa1\x7f\xfcG\xa4\x18\xcd\xff\xff\xff\xff1|~i\x00\xb3. ,1Q\x0e\xff\xff\xff\xff\x87a\x933Y\xd7\xe1B#\xa7a\xee\xff\xff\xff\xff\r\tJ\x18\xd0\xdb\x0b\xbe\x00\x91\x95\x9e\xff\xff\xff\xffHfW\xcd\x8f\xa9z6|\xc5\x171\xff\xff\xff\xff\xf5tP7\x93\x02Q|x\x17\xb1\xcb\xff\xff\xff\xffVb\x11\xa0*\xd9;\x0b\xf8\x1c\xd3c\xff\xff\xff\xff\x84\x82\xcer\x15\x99`5LmA\xd5\xff\xff\xff\xfft\xce\x8e\xcbw\xee\xf3\xc0w\xca\xb3\xfd\xff\xff\xff\xff\xb0\xaab\x92\xd4\x02\x84H3\x94\xa9~\xff\xff\xff\xff\xfe7\x18\xcaW=\x94\xbc|\x0f{\x84\xff\xff\xff\xff\xe8\xdf\xde?\x8b\xb7\x9dH3\xc1\xf2\xaa\xff\xff\xff\xff\xbe\x00\xba\xd7\xba6!\x95g\xb01\xf9\xff\xff\xff\xff\x93\xe3\x90YH9g\xf7\x97nhv\xff\xff\xff\xff\x82\xc7`\xaebn\x9d\x1e}\xba\x1e/\xff\xff\xff\xff\xbd\xe5\xa1\x05\x03\xf26\xa0\xe2\xc1*\x07\xff\xff\xff\xffny\x88\x9f\x19\xd2\xd0\xf7\x1de\xa7\xe0\xff\xff\xff\xff\xc4O&\x14\x8dVH\x90\x8b+\x03\xf9\xff\xff\xff\xff\xf69\xc2\xabo%\xcc/\xc9\xe4dP\xff\xff\xff\xff (\x08G\xebM\x03\x99Y\xb4\xb3\x1f\xff\xff\xff\xffzH\xd2\x19p#\xc5\xa4)\xfd\x05\x9a\xff\xff\xff\xffd\x86\xb2F\x15\x0f\xf4.\xfd\\\xd4#\xff\xff\xff\xff\xaf\xbe\xc6\x9di\xa0\xbc\xd5>cp\xe2\xff\xff\xff\xff&h\x91\xe9\xa0H\xdd\xaer\x87\x18E\xff\xff\xff\xffjg\x08E\x8f\xa4&\xab\xff\x98\x0ei\xff\xff\xff\xff\x01\xfd{"\xed\\\xa3M\x9e\xc3\xf8K\xff\xff\xff\xff\x87Y\x98T\xf0\xa6\xec\x98\xb3\xef\xa7\xaa\xff\xff\xff\xffA\xced\xfal\xd3\xd9\x06\xc6~\xee}\xff\xff\xff\xff:\x7f\xa2\x10\xc7\xadB,}PF%\xff\xff\xff\xff\xb2\xbc\n\x17%\x98\x904\x89\tF\x1f\xff\xff\xff\xff\xdc\xd8\xc6@#M\x87uf\x02\xc6g\xff\xff\xff\xffK\xaf\xb0-=l\x07\xe1Nv\xe4\xf4\xff\xff\xff\xff\xdb\x13\'Ne\xb2UT\x9a#\xb1^\xff\xff\xff\xff\xb2\rne\xd1\x9d\x88\xda\xbb!\xfa@\xff\xff\xff\xffflq\x0f\x01z]uh\'|?\xff\xff\xff\xff\xd5\'\x19\x865\xba\xf2\xe7\x8fR-\xcc\xff\xff\xff\xff\xce\xd6\xfdi\x04\x9b\xa7\tu\x05\xb7\xc8\xff\xff\xff\xff\xc3\xd0)\x11\xdd\xb1\xa5kp\xc9\xd5\xf7\xff\xff\xff\xff\xffU\x9f \xb7\xa1#3rup[\xff\xff\xff\xff\xfc='  # noqa

        request = RequestFactory().post('/')
        request.user = self.user
        error, instance = safe_create_instance(self.user.username,
                                               TempFileProxy(xml), None, None,
                                               request)
        text = 'File likely corrupted during transmission'
        self.assertContains(error, text, status_code=400)
예제 #19
0
        def build_sections(current_section,
                           survey_element,
                           sections,
                           select_multiples,
                           gps_fields,
                           encoded_fields,
                           field_delimiter='/'):
            for child in survey_element.children:
                current_section_name = current_section['name']
                # if a section, recurs
                if isinstance(child, Section):
                    # if its repeating, build a new section
                    if isinstance(child, RepeatingSection):
                        # section_name in recursive call changes
                        section = {
                            'name': child.get_abbreviated_xpath(),
                            'elements': []
                        }
                        self.sections.append(section)
                        build_sections(section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, field_delimiter)
                    else:
                        # its a group, recurs using the same section
                        build_sections(current_section, child, sections,
                                       select_multiples, gps_fields,
                                       encoded_fields, field_delimiter)
                elif isinstance(child, Question) and child.bind.get(u"type")\
                        not in QUESTION_TYPES_TO_EXCLUDE:
                    # add to survey_sections
                    if isinstance(child, Question):
                        child_xpath = child.get_abbreviated_xpath()
                        current_section['elements'].append({
                            'title':
                            ExportBuilder.format_field_title(
                                child.get_abbreviated_xpath(),
                                field_delimiter),
                            'xpath':
                            child_xpath,
                            'type':
                            child.bind.get(u"type")
                        })

                        if MongoHelper.is_attribute_invalid(child_xpath):
                            if current_section_name not in encoded_fields:
                                encoded_fields[current_section_name] = {}
                            encoded_fields[current_section_name].update(
                                {child_xpath: MongoHelper.encode(child_xpath)})

                    # if its a select multiple, make columns out of its choices
                    if child.bind.get(u"type") == MULTIPLE_SELECT_BIND_TYPE\
                            and self.SPLIT_SELECT_MULTIPLES:
                        for c in child.children:
                            _xpath = c.get_abbreviated_xpath()
                            _title = ExportBuilder.format_field_title(
                                _xpath, field_delimiter)
                            choice = {
                                'title': _title,
                                'xpath': _xpath,
                                'type': 'string'
                            }

                            if choice not in current_section['elements']:
                                current_section['elements'].append(choice)
                        _append_xpaths_to_section(
                            current_section_name, select_multiples,
                            child.get_abbreviated_xpath(), [
                                c.get_abbreviated_xpath()
                                for c in child.children
                            ])

                    # split gps fields within this section
                    if child.bind.get(u"type") == GEOPOINT_BIND_TYPE:
                        # add columns for geopoint components
                        xpaths = DataDictionary.get_additional_geopoint_xpaths(
                            child.get_abbreviated_xpath())
                        current_section['elements'].extend([{
                            'title':
                            ExportBuilder.format_field_title(
                                xpath, field_delimiter),
                            'xpath':
                            xpath,
                            'type':
                            'decimal'
                        } for xpath in xpaths])
                        _append_xpaths_to_section(
                            current_section_name, gps_fields,
                            child.get_abbreviated_xpath(), xpaths)
예제 #20
0
class TestSimpleSubmission(TestCase):
    def setUp(self):
        self.user = User.objects.create(username="******",
                                        email="*****@*****.**")
        self.user.set_password("pass")
        self.xform1 = DataDictionary()
        self.xform1.user = self.user
        self.xform1.json = '{"id_string": "yes_or_no", "children": [{"name": '\
                           '"yesno", "label": "Yes or no?", "type": "text"}],'\
                           ' "name": "yes_or_no", "title": "yes_or_no", "type'\
                           '": "survey"}'.strip()
        self.xform2 = DataDictionary()
        self.xform2.user = self.user
        self.xform2.json = '{"id_string": "start_time", "children": [{"name":'\
                           '"start_time", "type": "start"}], "name": "start_t'\
                           'ime", "title": "start_time", "type": "survey"}'\
                           .strip()

        def get_xml_for_form(xform):
            builder = SurveyElementBuilder()
            sss = builder.create_survey_element_from_json(xform.json)
            xform.xml = sss.to_xml()
            xform._mark_start_time_boolean()
            xform.save()

        get_xml_for_form(self.xform1)
        get_xml_for_form(self.xform2)

    def tearDown(self):
        self.xform1.delete()
        self.user.delete()

    def test_start_time_boolean_properly_set(self):
        self.assertFalse(self.xform1.has_start_time)
        self.assertTrue(self.xform2.has_start_time)

    def test_simple_yes_submission(self):
        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>'), [])

        self.assertEquals(0, self.xform1.instances.count())
        submit_simple_yes()
        self.assertEquals(1, self.xform1.instances.count())
        # a simple "yes" submission *SHOULD* increment the survey count
        submit_simple_yes()
        self.assertEquals(2, self.xform1.instances.count())

    def test_start_time_submissions(self):
        """
        This test checks to make sure that instances
        *with start_time available* are marked as duplicates when the XML is a
        direct match.
        """
        def submit_at_hour(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

        self.assertEquals(0, self.xform2.instances.count())
        submit_at_hour(11)
        self.assertEquals(1, self.xform2.instances.count())
        submit_at_hour(12)
        self.assertEquals(2, self.xform2.instances.count())
        # an instance from 11 AM already exists in the database, so it
        # *SHOULD NOT* increment the survey count.
        submit_at_hour(11)
        self.assertEquals(2, self.xform2.instances.count())