コード例 #1
0
ファイル: views.py プロジェクト: tobiasmcnulty/commcare-hq
    def post(self, request, *args, **kwargs):
        upload = request.FILES.get('bulk_upload_file')
        if not upload:
            messages.error(request, _('no file uploaded'))
            return self.get(request, *args, **kwargs)
        if not args:
            messages.error(request, _('no domain specified'))
            return self.get(request, *args, **kwargs)

        if not upload.name.endswith('.xlsx'):
            messages.error(request, _("Invalid file-format. Please upload a valid xlsx file."))
            return self.get(request, *args, **kwargs)

        try:
            get_workbook(upload)
        except WorkbookJSONError as e:
            messages.error(request, e)
            return self.get(request, *args, **kwargs)

        domain = args[0]

        ref = self._cache_file(request, domain, upload)
        if not isinstance(ref, LocationImportView.Ref):
            # ref is HTTP response: lock could not be acquired
            return ref
        file_ref = ref.value
        task = import_locations_async.delay(domain, file_ref.download_id, request.couch_user.user_id)
        file_ref.set_task(task)
        return HttpResponseRedirect(
            reverse(
                LocationImportStatusView.urlname,
                args=[domain, file_ref.download_id]
            )
        )
コード例 #2
0
def upload_bulk_app_translations(request, domain, app_id):
    lang = request.POST.get('language')
    validate = request.POST.get('validate')

    app = get_app(domain, app_id)
    workbook = None
    msgs = []
    try:
        workbook = get_workbook(request.file)
    except WorkbookJSONError as e:
        messages.error(request, six.text_type(e))

    if workbook:
        if validate:
            msgs = validate_bulk_app_translation_upload(app, workbook, request.user.email, lang)
        else:
            headers = get_bulk_app_sheet_headers(app, lang=lang)
            msgs = process_bulk_app_translation_upload(app, workbook, headers, lang=lang)
            app.save()

    for msg in msgs:
        # Add the messages to the request object.
        # msg[0] should be a function like django.contrib.messages.error .
        # msg[1] should be a string.
        msg[0](request, msg[1])

    # In v2, languages is the default tab on the settings page
    return HttpResponseRedirect(
        reverse('app_settings', args=[domain, app_id])
    )
コード例 #3
0
ファイル: views.py プロジェクト: tstalka/commcare-hq
def upload_bulk_app_translations(request, domain, app_id):
    lang = request.POST.get('language')
    validate = request.POST.get('validate')

    app = get_app(domain, app_id)
    try:
        workbook = get_workbook(request.file)
    except WorkbookJSONError as e:
        messages.error(request, str(e))
    else:
        if validate:
            if not lang:
                msgs = [(messages.error,
                         _("Please select language to validate."))]
            else:
                msgs = validate_bulk_app_translation_upload(
                    app, workbook, request.user.email, lang)
        else:
            sheet_name_to_unique_id = get_sheet_name_to_unique_id_map(
                request.file, lang)
            msgs = process_bulk_app_translation_upload(app,
                                                       workbook,
                                                       sheet_name_to_unique_id,
                                                       lang=lang)
            app.save()
        _add_messages_to_request(request, msgs)

    # In v2, languages is the default tab on the settings page
    return HttpResponseRedirect(reverse('app_settings', args=[domain, app_id]))
コード例 #4
0
    def test_upload(self):
        headers = (("translations", ("id", "name", "case_type")), )
        data = (("translations", (
            (self.translated_rule.id, 'test updated', 'song'),
            (self.email_rule.id, 'test email', 'song'),
            (1000, 'Not a rule', 'person'),
        )), )
        file = BytesIO()
        export_raw(headers, data, file, format=Format.XLS_2007)

        with tempfile.TemporaryFile(suffix='.xlsx') as f:
            f.write(file.getvalue())
            f.seek(0)
            workbook = get_workbook(f)
            msgs = [
                m[1] for m in upload_conditional_alert_rows(
                    self.domain, workbook.get_worksheet())
            ]
            self.assertEqual(len(msgs), 3)
            self._assertPatternIn(
                r"Row 3, with rule id \d+, does not use SMS content", msgs)
            self._assertPatternIn(
                r"Could not find rule for row 4, with id \d+", msgs)
            self.assertIn("Updated 1 rule(s)", msgs)
            self.assertEqual(self.translated_rule.name, 'test updated')
            self.assertEqual(self.translated_rule.case_type, 'song')
            self.assertEqual(self.untranslated_rule.name, 'test')
            self.assertEqual(self.untranslated_rule.case_type, 'person')
コード例 #5
0
ファイル: views.py プロジェクト: marionumza/commcare-hq
 def uploaded_file(self):
     try:
         bulk_file = self.request.FILES['bulk_upload_file']
     except KeyError:
         raise BulkUploadCasesException(_("No files uploaded"))
     try:
         return get_workbook(bulk_file)
     except WorkbookJSONError as e:
         raise BulkUploadCasesException(str(e))
コード例 #6
0
ファイル: views.py プロジェクト: dimagi/commcare-hq
 def uploaded_file(self):
     try:
         bulk_file = self.request.FILES['bulk_upload_file']
     except KeyError:
         raise BulkUploadCasesException(_("No files uploaded"))
     try:
         return get_workbook(bulk_file)
     except WorkbookJSONError as e:
         raise BulkUploadCasesException(six.text_type(e))
コード例 #7
0
    def post(self, request, *args, **kwargs):
        try:
            workbook = get_workbook(request.FILES['bulk_upload_file'])
        except WorkbookJSONError as e:
            messages.error(request, str(e))
            return self.get(request, *args, **kwargs)

        msgs = upload_conditional_alert_workbook(self.domain, workbook)
        for msg in msgs:
            msg[0](request, msg[1])

        return self.get(request, *args, **kwargs)
コード例 #8
0
 def test_validate_parents(self, location_type_mock, locations_mock, *_):
     location_type_mock.by_domain.return_value = self.location_types
     location_type_mock.select_related.return_value.filter.return_value = self.location_types
     locations_mock.select_related.return_value.filter.return_value = [
         Location(site_code='13', location_type=self.state_location_type)
     ]
     with tempfile.TemporaryFile() as file:
         export_raw(self.headers, self.rows, file, format=Format.XLS_2007)
         file.seek(0)
         workbook = get_workbook(file)
         parser = Parser(self.domain, workbook)
         errors = parser.parse()
         self.assertIn('Unexpected non-state parent 1 set for supervisor', errors, "missing location found")
         self.assertIn('Unexpected state parent 13 set for awc', errors, "incorrect parent type not flagged")
         self.assertIn('Parent 12 is marked for archival', errors, "archived parent not caught")
コード例 #9
0
 def test_validate_new_site_codes_type(self, location_type_mock, locations_mock, *_):
     location_type_mock.by_domain.return_value = self.location_types
     location_type_mock.select_related.return_value.filter.return_value = self.location_types
     locations_mock.select_related.return_value.filter.return_value = [
         Location(site_code='13', location_type=self.state_location_type)
     ]
     with tempfile.TemporaryFile() as file:
         export_raw(self.headers, self.rows, file, format=Format.XLS_2007)
         file.seek(0)
         workbook = get_workbook(file)
         parser = Parser(self.domain, workbook)
         errors = parser.parse()
         self.assertIn('state 13 used as supervisor', errors)
         self.assertIn('state 13 used as awc', errors)
         self.assertNotIn('state 13 used as state', errors)
コード例 #10
0
    def _upload(self, data, headers=None):
        if headers is None:
            headers = (
                ("translated", ("id", "name", "message_en", "message_es")),
                ("not translated", ("id", "name", "message")),
            )

        file = BytesIO()
        export_raw(headers, data, file, format=Format.XLS_2007)

        with tempfile.TemporaryFile(suffix='.xlsx') as f:
            f.write(file.getvalue())
            f.seek(0)
            workbook = get_workbook(f)
            msgs = upload_conditional_alert_workbook(self.domain, workbook)
            return [m[1] for m in msgs]     # msgs is tuples of (type, message); ignore the type
コード例 #11
0
ファイル: ui_translations.py プロジェクト: ye-man/commcare-hq
def process_ui_translation_upload(app, trans_file):
    trans_dict = defaultdict(dict)
    # Use this to hard fail and not update any translations
    error_properties = []
    # Use this to pass warnings without failing hard
    warnings = []

    try:
        workbook = get_workbook(trans_file)
    except WorkbookJSONError as e:
        error_properties.append(six.text_type(e))
        return trans_dict, error_properties, warnings

    commcare_version = get_commcare_version_from_workbook(workbook.wb)
    try:
        translations = workbook.get_worksheet(title='translations')
    except WorksheetNotFound:
        error_properties.append(
            _('Could not find sheet "translations" in uploaded file.'))
        return trans_dict, error_properties, warnings

    commcare_ui_strings = list(
        load_translations('en', version=2,
                          commcare_version=commcare_version).keys())
    default_trans = get_default_translations_for_download(
        app, commcare_version)
    lang_with_defaults = app.langs[get_index_for_defaults(app.langs)]

    for row in translations:
        if row["property"] not in commcare_ui_strings:
            # Add a warning for  unknown properties, but still add them to the translation dict
            warnings.append(
                row["property"] +
                " is not a known CommCare UI string, but we added it anyway")
        for lang in app.langs:
            if row.get(lang):
                all_parameters = re.findall(r"\$.*?}", row[lang])
                for param in all_parameters:
                    if not re.match(r"\$\{[0-9]+}", param):
                        error_properties.append(row["property"] + ' - ' +
                                                row[lang])
                if not (lang_with_defaults == lang and row[lang]
                        == default_trans.get(row["property"], "")):
                    trans_dict[lang].update({row["property"]: row[lang]})

    return trans_dict, error_properties, warnings
コード例 #12
0
ファイル: users.py プロジェクト: tstalka/commcare-hq
    def post(self, request, *args, **kwargs):
        """View's dispatch method automatically calls this"""
        try:
            self.workbook = get_workbook(request.FILES.get('bulk_upload_file'))
        except WorkbookJSONError as e:
            messages.error(request, str(e))
            return self.get(request, *args, **kwargs)

        try:
            self.user_specs = self.workbook.get_worksheet(title='users')
        except WorksheetNotFound:
            try:
                self.user_specs = self.workbook.get_worksheet()
            except WorksheetNotFound:
                return HttpResponseBadRequest("Workbook has no worksheets")

        try:
            self.group_specs = self.workbook.get_worksheet(title='groups')
        except WorksheetNotFound:
            self.group_specs = []

        try:
            check_headers(self.user_specs)
        except UserUploadError as e:
            messages.error(request, _(str(e)))
            return HttpResponseRedirect(
                reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        task_ref = expose_cached_download(payload=None,
                                          expiry=1 * 60 * 60,
                                          file_extension=None)
        task = import_users_and_groups.delay(
            self.domain,
            list(self.user_specs),
            list(self.group_specs),
        )
        task_ref.set_task(task)
        return HttpResponseRedirect(
            reverse(UserUploadStatusView.urlname,
                    args=[self.domain, task_ref.download_id]))
コード例 #13
0
 def test_parser(self, location_type_mock, _):
     type_codes = ['state', 'supervisor', 'awc']
     location_type_mock.return_value = list(
         map(lambda site_code: LocationType(code=site_code), type_codes))
     with tempfile.TemporaryFile() as file:
         export_raw(self.headers, self.rows, file, format=Format.XLS_2007)
         file.seek(0)
         workbook = get_workbook(file)
         parser = Parser(self.domain, workbook)
         errors = parser.parse()
         self.assertEqual(parser.valid_transitions['awc']['Move'],
                          {'131': '112'})
         self.assertEqual(parser.valid_transitions['awc']['Merge'],
                          {'132': ['113', '114']})
         self.assertEqual(parser.valid_transitions['supervisor']['Move'],
                          {'13': '12'})
         self.assertEqual(errors, [
             "No change in location code for Extract, got old: '111' and new: '111'",
             "New location 132 reused with different information",
             "Missing location code for Split, got old: '11' and new: ''",
             "Invalid Operation Unknown"
         ])
コード例 #14
0
ファイル: ui_translations.py プロジェクト: dimagi/commcare-hq
def process_ui_translation_upload(app, trans_file):
    trans_dict = defaultdict(dict)
    # Use this to hard fail and not update any translations
    error_properties = []
    # Use this to pass warnings without failing hard
    warnings = []

    try:
        workbook = get_workbook(trans_file)
    except WorkbookJSONError as e:
        error_properties.append(six.text_type(e))
        return trans_dict, error_properties, warnings

    commcare_version = get_commcare_version_from_workbook(workbook.wb)
    try:
        translations = workbook.get_worksheet(title='translations')
    except WorksheetNotFound:
        error_properties.append(_('Could not find sheet "translations" in uploaded file.'))
        return trans_dict, error_properties, warnings

    commcare_ui_strings = list(load_translations('en', version=2, commcare_version=commcare_version).keys())
    default_trans = get_default_translations_for_download(app, commcare_version)
    lang_with_defaults = app.langs[get_index_for_defaults(app.langs)]

    for row in translations:
        if row["property"] not in commcare_ui_strings:
            # Add a warning for  unknown properties, but still add them to the translation dict
            warnings.append(row["property"] + " is not a known CommCare UI string, but we added it anyway")
        for lang in app.langs:
            if row.get(lang):
                all_parameters = re.findall(r"\$.*?}", row[lang])
                for param in all_parameters:
                    if not re.match(r"\$\{[0-9]+}", param):
                        error_properties.append(row["property"] + ' - ' + row[lang])
                if not (lang_with_defaults == lang and
                        row[lang] == default_trans.get(row["property"], "")):
                    trans_dict[lang].update({row["property"]: row[lang]})

    return trans_dict, error_properties, warnings
コード例 #15
0
 def test_get_workbook(self):
     formula_filepath = self.get_path('formula_sheet', 'xlsx')
     workbook = get_workbook(formula_filepath)
     self.assertEquals(len(workbook.worksheets), 1)
     self.assertListEqual([row['name'] for row in workbook.worksheets[0]], ['ben'])
コード例 #16
0
ファイル: test_excel.py プロジェクト: tstalka/commcare-hq
 def test_get_workbook_duplicate_columns(self):
     bad_filepath = self.get_path('duplicate_columns', 'xlsx')
     with self.assertRaises(WorkbookJSONError):
         get_workbook(bad_filepath)
コード例 #17
0
ファイル: test_excel.py プロジェクト: tstalka/commcare-hq
 def test_get_workbook_bad_file(self):
     bad_filepath = self.get_path('not_excel_file', 'xlsx')
     with self.assertRaises(WorkbookJSONError):
         get_workbook(bad_filepath)
コード例 #18
0
ファイル: test_excel.py プロジェクト: tstalka/commcare-hq
 def test_get_workbook(self):
     formula_filepath = self.get_path('formula_sheet', 'xlsx')
     workbook = get_workbook(formula_filepath)
     self.assertEqual(len(workbook.worksheets), 1)
     self.assertListEqual([row['name'] for row in workbook.worksheets[0]],
                          ['ben'])
コード例 #19
0
 def test_get_workbook_duplicate_columns(self):
     bad_filepath = self.get_path('duplicate_columns', 'xlsx')
     with self.assertRaises(WorkbookJSONError):
         get_workbook(bad_filepath)
コード例 #20
0
    def post(self, request, *args, **kwargs):
        """View's dispatch method automatically calls this"""
        try:
            self.workbook = get_workbook(request.FILES.get('bulk_upload_file'))
        except WorkbookJSONError as e:
            messages.error(request, six.text_type(e))
            return self.get(request, *args, **kwargs)

        try:
            self.user_specs = self.workbook.get_worksheet(title='users')
        except WorksheetNotFound:
            try:
                self.user_specs = self.workbook.get_worksheet()
            except WorksheetNotFound:
                return HttpResponseBadRequest("Workbook has no worksheets")

        try:
            self.group_specs = self.workbook.get_worksheet(title='groups')
        except WorksheetNotFound:
            self.group_specs = []

        try:
            check_headers(self.user_specs)
        except UserUploadError as e:
            messages.error(request, _(six.text_type(e)))
            return HttpResponseRedirect(reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        # convert to list here because iterator destroys the row once it has
        # been read the first time
        self.user_specs = list(self.user_specs)

        for user_spec in self.user_specs:
            try:
                user_spec['username'] = enforce_string_type(user_spec['username'])
            except StringTypeRequiredError:
                messages.error(
                    request,
                    _("Error: Expected username to be a Text type for username {0}")
                    .format(user_spec['username'])
                )
                return HttpResponseRedirect(reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        try:
            check_existing_usernames(self.user_specs, self.domain)
        except UserUploadError as e:
            messages.error(request, _(six.text_type(e)))
            return HttpResponseRedirect(reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        try:
            check_duplicate_usernames(self.user_specs)
        except UserUploadError as e:
            messages.error(request, _(six.text_type(e)))
            return HttpResponseRedirect(reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        task_ref = expose_cached_download(payload=None, expiry=1*60*60, file_extension=None)
        task = bulk_upload_async.delay(
            self.domain,
            self.user_specs,
            list(self.group_specs),
        )
        task_ref.set_task(task)
        return HttpResponseRedirect(
            reverse(
                UserUploadStatusView.urlname,
                args=[self.domain, task_ref.download_id]
            )
        )
コード例 #21
0
 def test_get_workbook_bad_file(self):
     bad_filepath = self.get_path('not_excel_file', 'xlsx')
     with self.assertRaises(WorkbookJSONError):
         get_workbook(bad_filepath)
コード例 #22
0
    def test_parser(self, location_type_mock, _):
        location_type_mock.by_domain.return_value = self.location_types
        location_type_mock.select_related.return_value.filter.return_value = self.location_types
        with tempfile.TemporaryFile() as file:
            export_raw(self.headers, self.rows, file, format=Format.XLS_2007)
            file.seek(0)
            workbook = get_workbook(file)
            parser = Parser(self.domain, workbook)
            errors = parser.parse()
            self.assertEqual(len(parser.valid_transitions['awc']), 2)
            awc_transitions = [attr.asdict(t) for t in parser.valid_transitions['awc']]
            self.assertEqual(
                awc_transitions,
                [
                    {
                        'domain': self.domain,
                        'location_type_code': 'awc',
                        'operation': 'Move',
                        'old_site_codes': ['112'],
                        'new_site_codes': ['131'],
                        'new_location_details': {
                            '131': {'name': 'AWC 3 [131]', 'parent_site_code': '13', 'lgd_code': 'AWC-131',
                                    'sub_district_name': None}},
                        'user_transitions': {'username2': 'username3'}
                    },
                    {
                        'domain': self.domain,
                        'location_type_code': 'awc',
                        'operation': 'Move',
                        'old_site_codes': ['115'],
                        'new_site_codes': ['133'],
                        'new_location_details': {
                            '133': {'name': 'AWC 8 [133]', 'parent_site_code': '12', 'lgd_code': 'AWC-133',
                                    'sub_district_name': None}},
                        'user_transitions': {'username6': 'username7'}
                    }

                ]
            )
            self.assertEqual(len(parser.valid_transitions['supervisor']), 1)
            supervisor_transition = attr.asdict(parser.valid_transitions['supervisor'][0])
            self.assertEqual(
                supervisor_transition,
                {'domain': self.domain,
                 'location_type_code': 'supervisor',
                 'operation': 'Move',
                 'old_site_codes': ['12'],
                 'new_site_codes': ['13'],
                 'new_location_details': {
                     '13': {
                         'name': 'Supervisor 3 [13]',
                         'parent_site_code': '1',
                         'lgd_code': 'Sup-13',
                         'sub_district_name': None
                     }
                 },
                 'user_transitions': {'username5': 'username6'}}
            )
            self.assertEqual(len(parser.valid_transitions['state']), 1)
            state_transition = attr.asdict(parser.valid_transitions['state'][0])
            self.assertEqual(
                state_transition,
                {'domain': self.domain,
                 'location_type_code': 'state',
                 'operation': 'Move',
                 'old_site_codes': ['2'],
                 'new_site_codes': ['3'],
                 'new_location_details': {
                     '3': {
                         'name': 'State 3',
                         'parent_site_code': '',
                         'lgd_code': '',
                         'sub_district_name': None
                     }
                 },
                 'user_transitions': {}}
            )
            self.assertEqual(errors, [
                "Invalid Operation Unknown",
                "Missing location code for operation Split. Got old: '11' and new: ''",
                "Got invalid location code 'invalid $ite #code' for operation Move",
                "Got invalid location code 'new-- $ite #code' for operation Move",
                "Got invalid parent location code '?--123--?' for new location "
                "'new-- $ite #code' for operation Move",
                "No change in location code for operation Extract. Got old: '111' and new: '111'",
                "New location 132 passed with different information",
                "Missing new location name for 134"
            ])
コード例 #23
0
    def test_dump(self, mock_active_site_codes_search,
                  mock_inactive_site_codes_search, mock_case_count,
                  mock_location_ids):
        mock_case_count.return_value = []
        transitions = {
            'awc': [
                Transition(domain=self.domain,
                           location_type_code='awc',
                           operation=MOVE_OPERATION,
                           old_site_codes=['111'],
                           new_site_codes=['112']),
                Transition(domain=self.domain,
                           location_type_code='awc',
                           operation=MERGE_OPERATION,
                           old_site_codes=['113', '114'],
                           new_site_codes=['115']),
                Transition(domain=self.domain,
                           location_type_code='awc',
                           operation=SPLIT_OPERATION,
                           old_site_codes=['116'],
                           new_site_codes=['117', '118']),
                Transition(domain=self.domain,
                           location_type_code='awc',
                           operation=EXTRACT_OPERATION,
                           old_site_codes=['119'],
                           new_site_codes=['120'])
            ],
            'supervisor': [
                Transition(domain=self.domain,
                           location_type_code='awc',
                           operation=MOVE_OPERATION,
                           old_site_codes=['12'],
                           new_site_codes=['13']),
            ],
            'state': {}
        }

        mock_location_ids.return_value = {
            '111': 'locationid111',
            '113': 'locationid113',
            '114': 'locationid114',
            '116': 'locationid116',
            '119': 'locationid119',
            '12': 'locationid12'
        }
        mock_active_site_codes_search.return_value.values_list.return_value = [
            '112', '115', '117'
        ]
        mock_inactive_site_codes_search.return_value.values_list.return_value = [
            '120'
        ]
        filestream = Dumper(self.domain).dump(transitions)
        workbook = get_workbook(filestream)
        awc_worksheet_rows = list(workbook.get_worksheet('awc'))
        supervisor_worksheet_rows = list(workbook.get_worksheet('supervisor'))
        self.assertEqual(supervisor_worksheet_rows, [{
            OLD_LOCATION_CODE_COLUMN: '12',
            TRANSITION_COLUMN: MOVE_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '13',
            MISSING_COLUMN: True,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }])
        self.assertEqual(awc_worksheet_rows, [{
            OLD_LOCATION_CODE_COLUMN: '111',
            TRANSITION_COLUMN: MOVE_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '112',
            MISSING_COLUMN: False,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }, {
            OLD_LOCATION_CODE_COLUMN: '113',
            TRANSITION_COLUMN: MERGE_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '115',
            MISSING_COLUMN: False,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }, {
            OLD_LOCATION_CODE_COLUMN: '114',
            TRANSITION_COLUMN: MERGE_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '115',
            MISSING_COLUMN: False,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }, {
            OLD_LOCATION_CODE_COLUMN: '116',
            TRANSITION_COLUMN: SPLIT_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '117',
            MISSING_COLUMN: False,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }, {
            OLD_LOCATION_CODE_COLUMN: '116',
            TRANSITION_COLUMN: SPLIT_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '118',
            MISSING_COLUMN: True,
            ARCHIVED_COLUMN: False,
            CASE_COUNT_COLUMN: 0
        }, {
            OLD_LOCATION_CODE_COLUMN: '119',
            TRANSITION_COLUMN: EXTRACT_OPERATION,
            NEW_LOCATION_CODE_COLUMN: '120',
            MISSING_COLUMN: True,
            ARCHIVED_COLUMN: True,
            CASE_COUNT_COLUMN: 0
        }])
コード例 #24
0
 def _get_workbook(self, uploaded_file, action_type):
     try:
         workbook = get_workbook(uploaded_file)
     except WorkbookJSONError as e:
         return None, [str(e)]
     return workbook, self._validate_workbook(workbook, action_type)
コード例 #25
0
 def _get_workbook(self, uploaded_file):
     try:
         workbook = get_workbook(uploaded_file)
     except WorkbookJSONError as e:
         return None, [str(e)]
     return workbook, self._workbook_is_valid(workbook)
コード例 #26
0
ファイル: ui_translations.py プロジェクト: twymer/commcare-hq
def process_ui_translation_upload(app, trans_file):
    trans_dict = defaultdict(dict)
    # Use this to hard fail and not update any translations
    error_properties = []
    # Use this to pass warnings without failing hard
    warnings = []

    try:
        workbook = get_workbook(trans_file)
    except WorkbookJSONError as e:
        error_properties.append(str(e))
        return trans_dict, error_properties, warnings

    commcare_version = get_commcare_version_from_workbook(workbook.wb)
    try:
        translations = workbook.get_worksheet(title='translations')
    except WorksheetNotFound:
        error_properties.append(
            _('Could not find sheet "translations" in uploaded file.'))
        return trans_dict, error_properties, warnings

    commcare_ui_strings = list(
        load_translations('en', version=2,
                          commcare_version=commcare_version).keys())
    default_trans = get_default_translations_for_download(
        app, commcare_version)
    lang_with_defaults = app.langs[get_index_for_defaults(app.langs)]

    # Find all of the ${0}-looking values in a translation.
    # Returns list like ["${0}", "${1}", ...]
    def _get_params(translation):
        if not translation:
            return []
        return re.findall(r"\$.*?}", translation)

    # Create a string version of all parameters in a translation, suitable both for
    # comparison and for displaying in an error message.
    def _get_params_text(params):
        if not params:
            return "no parameters"

        # Reduce parameter list to the numbers alone, a set like {'0', '1', '2'}
        numbers = {re.sub(r'\D', '', p) for p in params}

        # Sort numbers, so that re-ordering parameters doesn't trigger error
        numbers = sorted(numbers)

        # Re-join numbers into a string for display
        return ", ".join(["${{{}}}".format(num) for num in numbers])

    for row in translations:
        if row["property"] not in commcare_ui_strings:
            # Add a warning for  unknown properties, but still add them to the translation dict
            warnings.append("Property '" + row["property"] +
                            "' is not a known CommCare UI string, "
                            "but we added it anyway.")
        default = default_trans.get(row["property"])
        default_params_text = _get_params_text(
            _get_params(default)) if default else None
        for lang in app.langs:
            if row.get(lang):
                params = _get_params(row[lang])
                params_text = _get_params_text(params)
                for param in params:
                    if not re.match(r"\$\{[0-9]+}", param):
                        error_properties.append(
                            _("""
                            Could not understand '{param}' in {lang} value of '{prop}'.
                        """).format(param=param,
                                    lang=lang,
                                    prop=row["property"]))
                if default_params_text and params_text != default_params_text:
                    warnings.append(
                        _("""
                        Property '{prop}' should contain {expected} but {lang} value contains {actual}.
                    """).format(prop=row["property"],
                                expected=default_params_text,
                                lang=lang,
                                actual=params_text))
                if not (lang_with_defaults == lang and row[lang]
                        == default_trans.get(row["property"], "")):
                    trans_dict[lang].update({row["property"]: row[lang]})

    return trans_dict, error_properties, warnings
コード例 #27
0
    def test_dump(self, get_location_mock, get_household_case_ids_mock, case_accessor_mock, child_cases_mock):
        location = Location(site_code='123', location_id='123654789')
        get_location_mock.return_value = location
        get_household_case_ids_mock.return_value = ['1', '2']
        case_accessor_mock.return_value = CommCareCaseStub(
            '100', 'A House', {'hh_reg_date': '20/1/1988', 'hh_religion': 'Above All'})
        child_cases_mock.return_value = [
            CommCareCaseStub('101', 'A Person', {'age_at_reg': '4', 'sex': 'M'}),
            CommCareCaseStub('102', 'B Person', {'age_at_reg': '5', 'sex': 'F'}),
        ]
        transitions = [
            Transition(
                domain=self.domain,
                location_type_code='awc',
                operation=MOVE_OPERATION,
                old_site_codes=['111'],
                new_site_codes=['112']),
            Transition(
                domain=self.domain,
                location_type_code='awc',
                operation=MERGE_OPERATION,
                old_site_codes=['113', '114'],
                new_site_codes=['115']),
            Transition(
                domain=self.domain,
                location_type_code='awc',
                operation=SPLIT_OPERATION,
                old_site_codes=['116'],
                new_site_codes=['117', '118']),
            Transition(
                domain=self.domain,
                location_type_code='awc',
                operation=EXTRACT_OPERATION,
                old_site_codes=['119'],
                new_site_codes=['120'])
        ]

        filestream = Households(self.domain).dump(transitions)

        get_location_mock.assert_has_calls([
            call(domain='test', site_code='116'),
            call(domain='test', site_code='119')
        ])
        get_household_case_ids_mock.assert_has_calls([
            call(self.domain, location.location_id),
            call(self.domain, location.location_id)
        ])
        case_accessor_mock.assert_has_calls([
            call('1'), call('2')
        ])
        child_cases_mock.assert_has_calls([
            call(self.domain, '1', location.location_id, [PERSON_CASE_TYPE]),
            call(self.domain, '2', location.location_id, [PERSON_CASE_TYPE])
        ])

        workbook = get_workbook(filestream)
        self.assertEqual(len(workbook.worksheets), 2)
        expected_row = {
            AWC_NAME_COLUMN: '',
            AWC_CODE_COLUMN: '',
            'Name of Household': 'A House',
            'Date of Registration': '20/1/1988',
            'Religion': 'Above All',
            'Caste': '',
            'APL/BPL': '',
            'Number of Household Members': 2,
            HOUSEHOLD_MEMBER_DETAILS_COLUMN: 'A Person (4/M), B Person (5/F)',
            HOUSEHOLD_ID_COLUMN: '100'
        }
        worksheet1_rows = list(workbook.worksheets_by_title['116'])
        self.assertEqual(
            worksheet1_rows,
            [expected_row, expected_row]
        )
        worksheet2_rows = list(workbook.worksheets_by_title['119'])
        self.assertEqual(
            worksheet2_rows,
            [expected_row, expected_row]
        )