Beispiel #1
0
def update_adherence_confidence(request, domain):
    try:
        request_json = json.loads(request.body)
    except ValueError:
        return json_response({"error": "Malformed JSON"}, status_code=400)
    beneficiary_id = request_json.get("beneficiary_id")
    start_date = request_json.get("start_date")
    end_date = request_json.get("end_date")
    confidence_level = request_json.get("confidence_level")

    try:
        validate_beneficiary_id(beneficiary_id)
        validate_dates(start_date, end_date)
        validate_confidence_level(confidence_level)
        update_adherence_confidence_level(
            domain=domain,
            person_id=beneficiary_id,
            start_date=parse_datetime(start_date),
            end_date=parse_datetime(end_date),
            new_confidence=confidence_level,
        )
    except AdherenceException as e:
        return json_response({"error": e.message}, status_code=400)

    return json_response({"success": "Patient adherences updated."})
Beispiel #2
0
def stats_data(request):
    histo_type = request.GET.get('histogram_type')
    interval = request.GET.get("interval", "week")
    datefield = request.GET.get("datefield")
    individual_domain_limit = request.GET.get("individual_domain_limit[]") or 16

    if not request.GET.get("enddate"):  # datespan should include up to the current day when unspecified
        request.datespan.enddate += timedelta(days=1)

    params, __ = parse_args_for_es(request, prefix='es_')

    if histo_type == "domains":
        return json_response(get_domain_stats_data(params, request.datespan, interval=interval, datefield=datefield))

    if params:
        domain_results = es_domain_query(params, fields=["name"], size=99999, show_stats=False)
        domains = [d["fields"]["name"] for d in domain_results["hits"]["hits"]]

        if len(domains) <= individual_domain_limit:
            domain_info = [{"names": [d], "display_name": d} for d in domains]
        elif len(domains) < ES_MAX_CLAUSE_COUNT:
            domain_info = [{"names": [d for d in domains], "display_name": _("Domains Matching Filter")}]
        else:
            domain_info = [{
                "names": None,
                "display_name": _("All Domains (NOT applying filters. > %s projects)" % ES_MAX_CLAUSE_COUNT)
            }]
    else:
        domain_info = [{"names": None, "display_name": _("All Domains")}]

    stats_data = get_stats_data(domain_info, histo_type, request.datespan, interval=interval)
    return json_response(stats_data)
Beispiel #3
0
def data_types(request, domain, data_type_id):
    
    if data_type_id:
        data_type = FixtureDataType.get(data_type_id)

        assert(data_type.doc_type == FixtureDataType._doc_type)
        assert(data_type.domain == domain)

        if request.method == 'GET':
            return json_response(strip_json(data_type))

        elif request.method == 'PUT':
            new = FixtureDataType(domain=domain, **_to_kwargs(request))
            for attr in 'tag', 'name', 'fields':
                setattr(data_type, attr, getattr(new, attr))
            data_type.save()
            return json_response(strip_json(data_type))

        elif request.method == 'DELETE':
            for item in FixtureDataItem.by_data_type(domain, data_type.get_id):
                item.delete()
            data_type.delete()
            return json_response({})

    elif data_type_id is None:

        if request.method == 'POST':
            data_type = FixtureDataType(domain=domain, **_to_kwargs(request))
            data_type.save()
            return json_response(strip_json(data_type))

        elif request.method == 'GET':
            return json_response([strip_json(x) for x in FixtureDataType.by_domain(domain)])

    return HttpResponseBadRequest()
Beispiel #4
0
    def post(self, request, *args, **kwargs):

        def update_dataset_map(instance, dict_):
            for key, value in dict_.items():
                if key == 'datavalue_maps':
                    value = [DataValueMap(**v) for v in value]
                instance[key] = value

        try:
            new_dataset_maps = json.loads(request.POST['dataset_maps'])
            current_dataset_maps = get_dataset_maps(request.domain)
            i = -1
            for i, dataset_map in enumerate(current_dataset_maps):
                if i < len(new_dataset_maps):
                    # Update current dataset maps
                    update_dataset_map(dataset_map, new_dataset_maps[i])
                    dataset_map.save()
                else:
                    # Delete removed dataset maps
                    dataset_map.delete()
            if i + 1 < len(new_dataset_maps):
                # Insert new dataset maps
                for j in range(i + 1, len(new_dataset_maps)):
                    dataset_map = DataSetMap(domain=request.domain)
                    update_dataset_map(dataset_map, new_dataset_maps[j])
                    dataset_map.save()
            get_dataset_maps.clear(request.domain)
            return json_response({'success': _('DHIS2 DataSet Maps saved')})
        except Exception as err:
            return json_response({'error': str(err)}, status_code=500)
Beispiel #5
0
def patch_xform(request, domain, app_id, unique_form_id):
    patch = request.POST['patch']
    sha1_checksum = request.POST['sha1']
    case_references = _get_case_references(request.POST)

    app = get_app(domain, app_id)
    form = app.get_form(unique_form_id)

    current_xml = form.source
    if hashlib.sha1(current_xml.encode('utf-8')).hexdigest() != sha1_checksum:
        return json_response({'status': 'conflict', 'xform': current_xml})

    dmp = diff_match_patch()
    xform, _ = dmp.patch_apply(dmp.patch_fromText(patch), current_xml)
    save_xform(app, form, xform)
    if "case_references" in request.POST or "references" in request.POST:
        form.case_references = case_references

    response_json = {
        'status': 'ok',
        'sha1': hashlib.sha1(form.source.encode('utf-8')).hexdigest()
    }
    app.save(response_json)
    notify_form_changed(domain, request.couch_user, app_id, unique_form_id)
    return json_response(response_json)
Beispiel #6
0
def get_ledgers(request, domain):
    """
    Returns ledgers associated with a case in the format:
    {
        "section_id": {
            "product_id": amount,
            "product_id": amount,
            ...
        },
        ...
    }
    """
    case_id = request.REQUEST.get('case_id')
    if not case_id:
        return json_response(
            {'message': 'You must specify a case id to make this query.'},
            status_code=400
        )
    case = get_document_or_404(CommCareCase, domain, case_id)
    ledger_map = get_current_ledger_transactions(case._id)
    def custom_json_handler(obj):
        if isinstance(obj, StockTransaction):
            return obj.stock_on_hand
        return json_handler(obj)

    return json_response(
        {
            'entity_id': case_id,
            'ledger': ledger_map,
        },
        default=custom_json_handler,
    )
Beispiel #7
0
 def post(self, request, *args, **kwargs):
     try:
         export_id = self.commit(request)
     except Exception as e:
         if self.is_async:
             # todo: this can probably be removed as soon as
             # http://manage.dimagi.com/default.asp?157713 is resolved
             notify_exception(request, 'problem saving an export! {}'.format(str(e)))
             response = json_response({
                 'error': str(e) or type(e).__name__
             })
             response.status_code = 500
             return response
         elif isinstance(e, ExportAppException):
             return HttpResponseRedirect(request.META['HTTP_REFERER'])
         else:
             raise
     else:
         try:
             post_data = json.loads(self.request.body)
             url = self.export_home_url
             # short circuit to check if the submit is from a create or edit feed
             # to redirect it to the list view
             from corehq.apps.export.views.list import DashboardFeedListView, DailySavedExportListView
             if isinstance(self, DashboardFeedMixin):
                 url = reverse(DashboardFeedListView.urlname, args=[self.domain])
             elif post_data['is_daily_saved_export']:
                 url = reverse(DailySavedExportListView.urlname, args=[self.domain])
         except ValueError:
             url = self.export_home_url
         if self.is_async:
             return json_response({
                 'redirect': url,
             })
         return HttpResponseRedirect(url)
Beispiel #8
0
def release_build(request, domain, app_id, saved_app_id):
    is_released = request.POST.get('is_released') == 'true'
    if not is_released:
        if LatestEnabledBuildProfiles.objects.filter(build_id=saved_app_id).exists():
            return json_response({'error': _('Please disable any enabled profiles to un-release this build.')})
    ajax = request.POST.get('ajax') == 'true'
    saved_app = get_app(domain, saved_app_id)
    if saved_app.copy_of != app_id:
        raise Http404
    saved_app.is_released = is_released
    saved_app.is_auto_generated = False
    saved_app.save(increment_version=False)
    from corehq.apps.app_manager.signals import app_post_release
    app_post_release.send(Application, application=saved_app)

    if is_released:
        if saved_app.build_profiles and domain_has_privilege(domain, privileges.BUILD_PROFILES):
            create_build_files_for_all_app_profiles.delay(domain, saved_app_id)
        _track_build_for_app_preview(domain, request.couch_user, app_id, 'User starred a build')

    if ajax:
        return json_response({
            'is_released': is_released,
            'latest_released_version': get_latest_released_app_version(domain, app_id)
        })
    else:
        return HttpResponseRedirect(reverse('release_manager', args=[domain, app_id]))
Beispiel #9
0
def child_locations_for_select2(request, domain):
    id = request.GET.get('id')
    query = request.GET.get('name', '').lower()
    user = request.couch_user

    def loc_to_payload(loc):
        return {'id': loc.location_id, 'name': loc.display_name}

    if id:
        try:
            loc = SQLLocation.objects.get(location_id=id)
        except SQLLocation.DoesNotExist:
            return json_response(
                {'message': 'no location with id %s found' % id},
                status_code=404,
            )
        else:
            return json_response(loc_to_payload(loc))
    else:
        locs = []
        user_loc = user.get_sql_location(domain)

        if user_can_edit_any_location(user, request.project):
            locs = SQLLocation.objects.filter(domain=domain)
        elif user_loc:
            locs = user_loc.get_descendants(include_self=True)

        if locs != [] and query:
            locs = locs.filter(name__icontains=query)

        return json_response(map(loc_to_payload, locs[:10]))
Beispiel #10
0
def prepare_form_multimedia(request, domain):
    """Gets the download_id for the multimedia zip and sends it to the
    exportDownloadService in download_export.ng.js to begin polling for the
    zip file download.
    """
    form_or_case = request.POST.get('form_or_case')
    sms_export = json.loads(request.POST.get('sms_export'))
    permissions = ExportsPermissionsManager(form_or_case, domain, request.couch_user)
    permissions.access_download_export_or_404()

    view_helper = DownloadExportViewHelper.get(request, domain, form_or_case, sms_export)
    filter_form_data = json.loads(request.POST.get('form_data'))
    export_specs = json.loads(request.POST.get('exports'))
    try:
        filter_form = view_helper.get_filter_form(filter_form_data)
    except ExportFormValidationException:
        return json_response({
            'error': _("Please check that you've submitted all required filters."),
        })

    download = DownloadBase()
    export_object = view_helper.get_export(export_specs[0]['export_id'])
    task_kwargs = filter_form.get_multimedia_task_kwargs(export_object, download.download_id, filter_form_data)
    from corehq.apps.reports.tasks import build_form_multimedia_zip
    download.set_task(build_form_multimedia_zip.delay(**task_kwargs))

    return json_response({
        'success': True,
        'download_id': download.download_id,
    })
Beispiel #11
0
def non_administrative_locations_for_select2(request, domain):
    id = request.GET.get('id')
    query = request.GET.get('name', '').lower()
    if id:
        try:
            loc = SQLLocation.objects.get(location_id=id)
            if loc.domain != domain:
                raise SQLLocation.DoesNotExist()
        except SQLLocation.DoesNotExist:
            return json_response(
                {'message': 'no location with id %s found' % id},
                status_code=404,
            )
        else:
            return json_response(loc_to_payload(loc))

    locs = []
    user = request.couch_user

    user_loc = user.get_sql_location(domain)

    if user.is_domain_admin(domain):
        locs = SQLLocation.objects.filter(domain=domain, location_type__administrative=False)
    elif user_loc:
        locs = user_loc.get_descendants(include_self=True, location_type__administrative=False)

    if locs != [] and query:
        locs = locs.filter(name__icontains=query)

    return json_response(list(map(loc_to_payload, locs[:10])))
Beispiel #12
0
def reinvite_web_user(request, domain):
    invitation_id = request.POST['invite']
    try:
        invitation = DomainInvitation.get(invitation_id)
        invitation.send_activation_email()
        return json_response({'response': _("Invitation resent"), 'status': 'ok'})
    except ResourceNotFound:
        return json_response({'response': _("Error while attempting resend"), 'status': 'error'})
Beispiel #13
0
def filter_cases(request, domain, app_id, module_id):
    app = Application.get(app_id)
    module = app.get_module(module_id)
    delegation = request.GET.get('task-list') == 'true'
    auth_cookie = request.COOKIES.get('sessionid')

    suite_gen = SuiteGenerator(app)
    xpath = suite_gen.get_filter_xpath(module, delegation=delegation)
    extra_instances = [{'id': inst.id, 'src': inst.src}
                       for inst in suite_gen.get_instances_for_module(module, additional_xpaths=[xpath])]

    # touchforms doesn't like this to be escaped
    xpath = HTMLParser.HTMLParser().unescape(xpath)
    if delegation:
        case_type = DELEGATION_STUB_CASE_TYPE
    else:
        case_type = module.case_type

    if xpath:
        # if we need to do a custom filter, send it to touchforms for processing
        additional_filters = {
            "properties/case_type": case_type,
            "footprint": True
        }

        helper = SessionDataHelper(domain, request.couch_user)
        result = helper.filter_cases(xpath, additional_filters, DjangoAuth(auth_cookie),
                                     extra_instances=extra_instances)
        if result.get('status', None) == 'error':
            return HttpResponseServerError(
                result.get("message", _("Something went wrong filtering your cases.")))

        case_ids = result.get("cases", [])
    else:
        # otherwise just use our built in api with the defaults
        case_ids = [res.id for res in get_filtered_cases(
            domain, status=CASE_STATUS_OPEN, case_type=case_type,
            user_id=request.couch_user._id, ids_only=True
        )]

    cases = [CommCareCase.wrap(doc) for doc in iter_docs(CommCareCase.get_db(), case_ids)]
    # refilter these because we might have accidentally included footprint cases
    # in the results from touchforms. this is a little hacky but the easiest
    # (quick) workaround. should be revisted when we optimize the case list.
    cases = filter(lambda c: c.type == case_type, cases)
    cases = [c.get_json(lite=True) for c in cases if c]
    parents = []
    if delegation:
        for case in cases:
            parent_id = case['indices']['parent']['case_id']
            parents.append(CommCareCase.get(parent_id))
        return json_response({
            'cases': cases,
            'parents': parents
        })
    else:
        return json_response(cases)
Beispiel #14
0
def prepare_custom_export(request, domain):
    """Uses the current exports download framework (with some nasty filters)
    to return the current download id to POLL for the download status.
    :return: {
        'success': True,
        'download_id': '<some uuid>',
    }
    """
    form_or_case = request.POST.get('form_or_case')
    sms_export = json.loads(request.POST.get('sms_export'))
    permissions = ExportsPermissionsManager(form_or_case, domain, request.couch_user)
    permissions.access_download_export_or_404()

    view_helper = DownloadExportViewHelper.get(request, domain, form_or_case, sms_export)

    filter_form_data = json.loads(request.POST.get('form_data'))
    try:
        filter_form = view_helper.get_filter_form(filter_form_data)
    except ExportFormValidationException:
        return json_response({
            'error': _("Form did not validate."),
        })
    export_filters = filter_form.get_export_filters(request, filter_form_data)

    export_specs = json.loads(request.POST.get('exports'))
    export_ids = [spec['export_id'] for spec in export_specs]
    export_instances = [view_helper.get_export(export_id) for export_id in export_ids]

    try:
        _check_deid_permissions(permissions, export_instances)
        _check_export_size(domain, export_instances, export_filters)
    except ExportAsyncException as e:
        return json_response({
            'error': six.text_type(e),
        })

    # Generate filename
    if len(export_instances) > 1:
        filename = "{}_custom_bulk_export_{}".format(domain, date.today().isoformat())
    else:
        filename = "{} {}".format(export_instances[0].name, date.today().isoformat())

    download = get_export_download(
        domain,
        export_ids,
        view_helper.model,
        request.couch_user.username,
        filters=export_filters,
        filename=filename,
    )

    view_helper.send_preparation_analytics(export_instances, export_filters)

    return json_response({
        'success': True,
        'download_id': download.download_id,
    })
Beispiel #15
0
def reinvite_web_user(request, domain):
    invitation_id = request.POST["invite"]
    try:
        invitation = DomainInvitation.get(invitation_id)
        invitation.invited_on = datetime.utcnow()
        invitation.save()
        invitation.send_activation_email()
        return json_response({"response": _("Invitation resent"), "status": "ok"})
    except ResourceNotFound:
        return json_response({"response": _("Error while attempting resend"), "status": "error"})
Beispiel #16
0
def clear_data(request, mapping_id, domain=None):
    if mapping_id:
        try:
            mapping = SqlExtractMapping.get(mapping_id)
            get_extractor(mapping.backend).clear_all_data(mapping)
            return json_response({'status': 'success', 'message': _('Data successfully cleared.')})
        except ResourceNotFound:
            return json_response({'status': 'error', 'message': _('Mapping not found.')})

    return json_response({'status': 'error', 'message': _('Mapping not found.')})
Beispiel #17
0
def filter_cases(request, domain, app_id, module_id, parent_id=None):
    app = Application.get(app_id)
    module = app.get_module(module_id)
    auth_cookie = request.COOKIES.get('sessionid')

    suite_gen = SuiteGenerator(app)
    xpath = SuiteGenerator.get_filter_xpath(module)
    extra_instances = [{'id': inst.id, 'src': inst.src}
                       for inst in suite_gen.get_instances_for_module(module, additional_xpaths=[xpath])]

    # touchforms doesn't like this to be escaped
    xpath = HTMLParser.HTMLParser().unescape(xpath)
    case_type = module.case_type

    if xpath:
        # if we need to do a custom filter, send it to touchforms for processing
        additional_filters = {
            "properties/case_type": case_type,
            "footprint": True
        }

        helper = SessionDataHelper(domain, request.couch_user)
        result = helper.filter_cases(xpath, additional_filters, DjangoAuth(auth_cookie),
                                     extra_instances=extra_instances)
        if result.get('status', None) == 'error':
            code = result.get('code', 500)
            message = result.get('message', _("Something went wrong filtering your cases."))
            if code == 500:
                notify_exception(None, message=message)
            return json_response(message, status_code=code)

        case_ids = result.get("cases", [])
    else:
        # otherwise just use our built in api with the defaults
        case_ids = [res.id for res in get_filtered_cases(
            domain,
            status=CASE_STATUS_OPEN,
            case_type=case_type,
            user_id=request.couch_user._id,
            footprint=True,
            ids_only=True,
        )]

    cases = [CommCareCase.wrap(doc) for doc in iter_docs(CommCareCase.get_db(), case_ids)]

    if parent_id:
        cases = filter(lambda c: c.parent and c.parent.case_id == parent_id, cases)

    # refilter these because we might have accidentally included footprint cases
    # in the results from touchforms. this is a little hacky but the easiest
    # (quick) workaround. should be revisted when we optimize the case list.
    cases = filter(lambda c: c.type == case_type, cases)
    cases = [c.get_json(lite=True) for c in cases if c]

    return json_response(cases)
Beispiel #18
0
def submit_app_data_drilldown_form(request, domain):
    if json.loads(request.POST.get('is_deid')):
        raise Http404()

    model_type = request.POST.get('model_type')
    permissions = ExportsPermissionsManager(model_type, domain, request.couch_user)
    permissions.access_list_exports_or_404(is_deid=False)

    form_data = json.loads(request.POST.get('form_data'))
    is_daily_saved_export = json.loads(request.POST.get('is_daily_saved_export'))
    is_feed = json.loads(request.POST.get('is_feed'))

    create_form = CreateExportTagForm(
        permissions.has_form_export_permissions,
        permissions.has_case_export_permissions,
        form_data
    )
    if not create_form.is_valid():
        return json_response({
            'success': False,
            'error': _("The form did not validate."),
        })

    from corehq.apps.export.views.new import (
        CreateNewCaseFeedView,
        CreateNewCustomCaseExportView,
        CreateNewCustomFormExportView,
        CreateNewDailySavedCaseExport,
        CreateNewDailySavedFormExport,
        CreateNewFormFeedView,
    )

    if is_daily_saved_export:
        if create_form.cleaned_data['model_type'] == "case":
            export_tag = create_form.cleaned_data['case_type']
            cls = CreateNewCaseFeedView if is_feed else CreateNewDailySavedCaseExport
        else:
            export_tag = create_form.cleaned_data['form']
            cls = CreateNewFormFeedView if is_feed else CreateNewDailySavedFormExport
    elif model_type == 'form':
        export_tag = create_form.cleaned_data['form']
        cls = CreateNewCustomFormExportView
    elif model_type == 'case':
        export_tag = create_form.cleaned_data['case_type']
        cls = CreateNewCustomCaseExportView

    url_params = '?export_tag="{}"'.format(export_tag)
    app_id = create_form.cleaned_data['application']
    if app_id != ApplicationDataRMIHelper.UNKNOWN_SOURCE:
        url_params += '&app_id={}'.format(app_id)

    return json_response({
        'success': True,
        'url': reverse(cls.urlname, args=[domain]) + url_params,
    })
Beispiel #19
0
def system_ajax(request):
    """
    Utility ajax functions for polling couch and celerymon
    """
    type = request.GET.get('api', None)
    task_limit = getattr(settings, 'CELERYMON_TASK_LIMIT', 12)
    celery_monitoring = getattr(settings, 'CELERY_FLOWER_URL', None)
    db = XFormInstance.get_db()
    if type == "_active_tasks":
        tasks = [] if is_bigcouch() else filter(lambda x: x['type'] == "indexer", db.server.active_tasks())
        #for reference structure is:
        #        tasks = [{'type': 'indexer', 'pid': 'foo', 'database': 'mock',
        #            'design_document': 'mockymock', 'progress': 0,
        #            'started_on': 1349906040.723517, 'updated_on': 1349905800.679458,
        #            'total_changes': 1023},
        #            {'type': 'indexer', 'pid': 'foo', 'database': 'mock',
        #            'design_document': 'mockymock', 'progress': 70,
        #            'started_on': 1349906040.723517, 'updated_on': 1349905800.679458,
        #            'total_changes': 1023}]
        return json_response(tasks)
    elif type == "_stats":
        return json_response({})
    elif type == "_logs":
        pass
    elif type == 'pillowtop':
        return json_response(get_all_pillows_json())
    elif type == 'stale_pillows':
        es_index_status = [
            check_case_es_index(interval=3),
            check_xform_es_index(interval=3),
            check_reportcase_es_index(interval=3),
            check_reportxform_es_index(interval=3)
        ]
        return json_response(es_index_status)

    if celery_monitoring:
        cresource = Resource(celery_monitoring, timeout=3)
        if type == "flower_poll":
            ret = []
            try:
                t = cresource.get("api/tasks", params_dict={'limit': task_limit}).body_string()
                all_tasks = json.loads(t)
            except Exception, ex:
                all_tasks = {}
                logging.error("Error with getting from celery_flower: %s" % ex)

            for task_id, traw in all_tasks.items():
                # it's an array of arrays - looping through [<id>, {task_info_dict}]
                if 'name' in traw and traw['name']:
                    traw['name'] = '.'.join(traw['name'].split('.')[-2:])
                else:
                    traw['name'] = None
                ret.append(traw)
            ret = sorted(ret, key=lambda x: x['succeeded'], reverse=True)
            return HttpResponse(json.dumps(ret), mimetype = 'application/json')
Beispiel #20
0
def poll_state(request, domain=None, job_id=None):
    if not job_id:
        kwargs = {'domain': domain} if domain else {}
        return redirect('sql_mappings_list', **kwargs)

    job = AsyncResult(job_id)
    data = job.result or job.state
    try:
        return json_response(data)
    except TypeError:
        return json_response(dict(error=str(data)))
Beispiel #21
0
def run_command(request):
    cmd = request.POST.get('command')
    if cmd not in ['remove_duplicate_domains']: # only expose this one command for now
        return json_response({"success": False, "output": "Command not available"})

    output_buf = StringIO()
    management.call_command(cmd, stdout=output_buf)
    output = output_buf.getvalue()
    output_buf.close()

    return json_response({"success": True, "output": output})
Beispiel #22
0
def dismiss_notification(request):
    note_id = request.POST.get('note_id', None)
    note = Notification.get(note_id)
    if note:
        if note.user != request.couch_user.username:
            return json_response({"status": "failure: Not the same user"})

        note.dismissed = True
        note.save()
        return json_response({"status": "success"})
    return json_response({"status": "failure: No note by that name"})
Beispiel #23
0
def delete_user_role(request, domain):
    if not domain_has_privilege(domain, privileges.ROLE_BASED_ACCESS):
        return json_response({})
    role_data = json.loads(request.body)
    try:
        role = UserRole.get(role_data["_id"])
    except ResourceNotFound:
        return json_response({})
    copy_id = role._id
    role.delete()
    # return removed id in order to remove it from UI
    return json_response({"_id": copy_id})
Beispiel #24
0
def post_user_role(request, domain):
    if not domain_has_privilege(domain, privileges.ROLE_BASED_ACCESS):
        return json_response({})
    role_data = json.loads(request.raw_post_data)
    role_data = dict([(p, role_data[p]) for p in set(UserRole.properties().keys() + ['_id', '_rev']) if p in role_data])
    role = UserRole.wrap(role_data)
    role.domain = domain
    if role.get_id:
        old_role = UserRole.get(role.get_id)
        assert(old_role.doc_type == UserRole.__name__)
        assert(old_role.domain == domain)
    role.save()
    return json_response(role)
Beispiel #25
0
def post_user_role(request, domain):
    if not domain_has_privilege(domain, privileges.ROLE_BASED_ACCESS):
        return json_response({})
    role_data = json.loads(request.body)
    role_data = dict([(p, role_data[p]) for p in set(UserRole.properties().keys() + ["_id", "_rev"]) if p in role_data])
    role = UserRole.wrap(role_data)
    role.domain = domain
    if role.get_id:
        old_role = UserRole.get(role.get_id)
        assert old_role.doc_type == UserRole.__name__
        assert old_role.domain == domain
    role.save()
    role.__setattr__("hasUsersAssigned", True if len(role.ids_of_assigned_users) > 0 else False)
    return json_response(role)
Beispiel #26
0
def update_emailed_export_data(request, domain):

    permissions = ExportsPermissionsManager(request.GET.get('model_type'), domain, request.couch_user)
    permissions.access_list_exports_or_404(is_deid=json.loads(request.POST.get('is_deid')))

    export_instance_id = request.POST.get('export_id')
    try:
        rebuild_saved_export(export_instance_id, manual=True)
    except XlsLengthException:
        return json_response({
            'error': _('This file has more than 256 columns, which is not supported by xls. '
                       'Please change the output type to csv or xlsx in the export configuration page '
                       'to export this file.')
        })
    return json_response({'success': True})
Beispiel #27
0
def get_session_context(request, domain, session_id):
    try:
        session = EntrySession.objects.get(session_id=session_id)
    except EntrySession.DoesNotExist:
        session = None
    if request.method == 'DELETE':
        if session:
            session.delete()
        return json_response({'status': 'success'})
    else:
        helper = SessionDataHelper(domain, request.couch_user)
        return json_response(helper.get_full_context({
            'session_id': session_id,
            'app_id': session.app_id if session else None
        }))
Beispiel #28
0
def get_cases(request, domain):

    if request.couch_user.is_commcare_user():
        user_id = request.couch_user.get_id
    else:
        user_id = request.REQUEST.get("user_id", "")

    if not user_id and not request.couch_user.is_web_user():
        return HttpResponseBadRequest("Must specify user_id!")

    ids_only = string_to_boolean(request.REQUEST.get("ids_only", "false"))
    case_id = request.REQUEST.get("case_id", "")
    footprint = string_to_boolean(request.REQUEST.get("footprint", "false"))
    include_children = string_to_boolean(request.REQUEST.get("include_children", "false"))
    if case_id and not footprint and not include_children:
        # short circuit everything else and just return the case
        # NOTE: this allows any user in the domain to access any case given
        # they know its ID, which is slightly different from the previous
        # behavior (can only access things you own + footprint). If we want to
        # change this contract we would need to update this to check the
        # owned case list + footprint
        case = CommCareCase.get(case_id)
        assert case.domain == domain
        cases = [CaseAPIResult(id=case_id, couch_doc=case, id_only=ids_only)]
    else:
        filters = get_filters_from_request(request)
        status = api_closed_to_status(request.REQUEST.get('closed', 'false'))
        case_type = filters.get('properties/case_type', None)
        cases = get_filtered_cases(domain, status=status, case_type=case_type,
                                   user_id=user_id, filters=filters,
                                   footprint=footprint, ids_only=ids_only,
                                   strip_history=True, include_children=include_children)
    return json_response(cases)
Beispiel #29
0
def stats_data(request, org):
    params, _ = parse_args_for_es(request)
    domains = [{"name": d.name, "hr_name": d.hr_name} for d in Domain.get_by_organization(org).all()]
    histo_type = request.GET.get("histogram_type")
    period = request.GET.get("daterange", "month")

    today = date.today()
    startdate = today - timedelta(days={"month": 30, "week": 7, "quarter": 90, "year": 365}[period])

    histo_data = dict(
        [
            (
                d["hr_name"],
                es_histogram(histo_type, [d["name"]], startdate.strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d")),
            )
            for d in domains
        ]
    )

    return json_response(
        {
            "histo_data": histo_data,
            "range": period,
            "startdate": [startdate.year, startdate.month, startdate.day],
            "enddate": [today.year, today.month, today.day],
        }
    )
Beispiel #30
0
def stats_data(request):
    histo_type = request.GET.get('histogram_type')
    interval = request.GET.get("interval", "week")
    datefield = request.GET.get("datefield")
    get_request_params_json = request.GET.get("get_request_params", None)
    get_request_params = (
        json.loads(HTMLParser.HTMLParser().unescape(get_request_params_json))
        if get_request_params_json is not None else {}
    )

    stats_kwargs = {
        k: get_request_params[k]
        for k in get_request_params if k != "domain_params_es"
    }
    if datefield is not None:
        stats_kwargs['datefield'] = datefield

    domain_params_es = get_request_params.get("domain_params_es", {})

    if not request.GET.get("enddate"):  # datespan should include up to the current day when unspecified
        request.datespan.enddate += timedelta(days=1)

    domain_params, __ = parse_args_for_es(request, prefix='es_')
    domain_params.update(domain_params_es)

    domains = get_project_spaces(facets=domain_params)

    return json_response(get_stats_data(
        histo_type,
        domains,
        request.datespan,
        interval,
        **stats_kwargs
    ))
Beispiel #31
0
def get_apps_api(request, domain):
    return json_response(get_cloudcare_apps(domain))
Beispiel #32
0
def edit_module_attr(request, domain, app_id, module_unique_id, attr):
    """
    Called to edit any (supported) module attribute, given by attr
    """
    attributes = {
        "all": None,
        "auto_select_case": None,
        "case_list": ('case_list-show', 'case_list-label'),
        "case_list-menu_item_media_audio": None,
        "case_list-menu_item_media_image": None,
        "case_list_form_id": None,
        "case_list_form_label": None,
        "case_list_form_media_audio": None,
        "case_list_form_media_image": None,
        "case_list_post_form_workflow": None,
        "case_type": None,
        'comment': None,
        "display_separately": None,
        "has_schedule": None,
        "media_audio": None,
        "media_image": None,
        "module_filter": None,
        "name": None,
        "parent_module": None,
        "put_in_root": None,
        "root_module_id": None,
        "source_module_id": None,
        "task_list": ('task_list-show', 'task_list-label'),
        "excl_form_ids": None,
        "display_style": None,
        "custom_icon_form": None,
        "custom_icon_text_body": None,
        "custom_icon_xpath": None,
    }

    if attr not in attributes:
        return HttpResponseBadRequest()

    def should_edit(attribute):
        if attribute == attr:
            return True
        if 'all' == attr:
            if attributes[attribute]:
                for param in attributes[attribute]:
                    if not request.POST.get(param):
                        return False
                return True
            else:
                return request.POST.get(attribute) is not None

    app = get_app(domain, app_id)

    try:
        module = app.get_module_by_unique_id(module_unique_id)
    except ModuleNotFoundException:
        # temporary fallback
        module = app.get_module(module_unique_id)

    lang = request.COOKIES.get('lang', app.langs[0])
    resp = {'update': {}, 'corrections': {}}
    if should_edit("custom_icon_form"):
        error_message = handle_custom_icon_edits(request, module, lang)
        if error_message:
            return json_response(
                {'message': error_message},
                status_code=400
            )

    if should_edit("case_type"):
        case_type = request.POST.get("case_type", None)
        if case_type == USERCASE_TYPE and not isinstance(module, AdvancedModule):
            return HttpResponseBadRequest('"{}" is a reserved case type'.format(USERCASE_TYPE))
        elif case_type and not is_valid_case_type(case_type, module):
            return HttpResponseBadRequest("case type is improperly formatted")
        else:
            old_case_type = module["case_type"]
            module["case_type"] = case_type

            # rename other reference to the old case type
            all_advanced_modules = []
            modules_with_old_case_type_exist = False
            for mod in app.modules:
                if isinstance(mod, AdvancedModule):
                    all_advanced_modules.append(mod)

                modules_with_old_case_type_exist |= mod.case_type == old_case_type
            for mod in all_advanced_modules:
                for form in mod.forms:
                    for action in form.actions.get_load_update_actions():
                        if action.case_type == old_case_type and action.details_module == module_unique_id:
                            action.case_type = case_type

                    if mod.unique_id == module_unique_id or not modules_with_old_case_type_exist:
                        for action in form.actions.get_open_actions():
                            if action.case_type == old_case_type:
                                action.case_type = case_type

    if should_edit("put_in_root"):
        module["put_in_root"] = json.loads(request.POST.get("put_in_root"))
    if should_edit("display_style"):
        module["display_style"] = request.POST.get("display_style")
    if should_edit("source_module_id"):
        module["source_module_id"] = request.POST.get("source_module_id")
    if should_edit("display_separately"):
        module["display_separately"] = json.loads(request.POST.get("display_separately"))
    if should_edit("parent_module"):
        parent_module = request.POST.get("parent_module")
        module.parent_select.module_id = parent_module
        if module_case_hierarchy_has_circular_reference(module):
            return HttpResponseBadRequest(_("The case hierarchy contains a circular reference."))
    if should_edit("auto_select_case"):
        module["auto_select_case"] = request.POST.get("auto_select_case") == 'true'

    if app.enable_module_filtering and should_edit('module_filter'):
        module['module_filter'] = request.POST.get('module_filter')

    if should_edit('case_list_form_id'):
        module.case_list_form.form_id = request.POST.get('case_list_form_id')
    if should_edit('case_list_form_label'):
        module.case_list_form.label[lang] = request.POST.get('case_list_form_label')
    if should_edit('case_list_post_form_workflow'):
        module.case_list_form.post_form_workflow = request.POST.get('case_list_post_form_workflow')
    if should_edit('case_list_form_media_image'):
        new_path = process_media_attribute(
            'case_list_form_media_image',
            resp,
            request.POST.get('case_list_form_media_image')
        )
        module.case_list_form.set_icon(lang, new_path)

    if should_edit('case_list_form_media_audio'):
        new_path = process_media_attribute(
            'case_list_form_media_audio',
            resp,
            request.POST.get('case_list_form_media_audio')
        )
        module.case_list_form.set_audio(lang, new_path)

    if should_edit('case_list-menu_item_media_image'):
        val = process_media_attribute(
            'case_list-menu_item_media_image',
            resp,
            request.POST.get('case_list-menu_item_media_image')
        )
        module.case_list.set_icon(lang, val)
    if should_edit('case_list-menu_item_media_audio'):
        val = process_media_attribute(
            'case_list-menu_item_media_audio',
            resp,
            request.POST.get('case_list-menu_item_media_audio')
        )
        module.case_list.set_audio(lang, val)

    if should_edit("name"):
        name = request.POST.get("name", None)
        module["name"][lang] = name
        resp['update'] = {'.variable-module_name': trans(module.name, [lang], use_delim=False)}
    if should_edit('comment'):
        module.comment = request.POST.get('comment')
    for SLUG in ('case_list', 'task_list'):
        show = '{SLUG}-show'.format(SLUG=SLUG)
        label = '{SLUG}-label'.format(SLUG=SLUG)
        if request.POST.get(show) == 'true' and (request.POST.get(label) == ''):
            # Show item, but empty label, was just getting ignored
            return HttpResponseBadRequest("A label is required for {SLUG}".format(SLUG=SLUG))
        if should_edit(SLUG):
            module[SLUG].show = json.loads(request.POST[show])
            module[SLUG].label[lang] = request.POST[label]

    if should_edit("root_module_id"):
        if not request.POST.get("root_module_id"):
            module["root_module_id"] = None
        else:
            module["root_module_id"] = request.POST.get("root_module_id")

    if should_edit('excl_form_ids') and isinstance(module, ShadowModule):
        excl = request.POST.getlist('excl_form_ids')
        excl.remove('0')  # Placeholder value to make sure excl_form_ids is POSTed when no forms are excluded
        module.excluded_form_ids = excl

    handle_media_edits(request, module, should_edit, resp, lang)

    app.save(resp)
    resp['case_list-show'] = module.requires_case_details()
    return HttpResponse(json.dumps(resp))
Beispiel #33
0
def data_source_status(request, domain, config_id):
    config = get_document_or_404(DataSourceConfiguration, domain, config_id)
    return json_response({'isBuilt': config.meta.build.finished})
Beispiel #34
0
def get_app_api(request, domain, app_id):
    try:
        return json_response(look_up_app_json(domain, app_id))
    except RemoteAppError:
        raise Http404()
Beispiel #35
0
                instance_id).get_xml()
        except XFormNotFound:
            raise Http404()

    session_extras = {'session_name': session_name, 'app_id': app._id}
    session_extras.update(
        get_cloudcare_session_data(domain, form, request.couch_user))

    delegation = request.GET.get('task-list') == 'true'
    session_helper = CaseSessionDataHelper(domain,
                                           request.couch_user,
                                           case_id,
                                           app,
                                           form,
                                           delegation=delegation)
    return json_response(
        session_helper.get_full_context(root_context, session_extras))


cloudcare_api = login_or_digest_ex(allow_cc_users=True)


def get_cases_vary_on(request, domain):
    request_params = request.GET

    return [
        request.couch_user.get_id if request.couch_user.is_commcare_user() else
        request_params.get('user_id', ''),
        request_params.get('ids_only', 'false'),
        request_params.get('case_id', ''),
        request_params.get('footprint', 'false'),
        request_params.get('closed', 'false'),
Beispiel #36
0
def app_source(request, domain, app_id):
    app = get_app(domain, app_id)
    return json_response(app.export_json(dump_json=False))
Beispiel #37
0
def location_descendants_count(request, domain, loc_id):
    loc = get_object_or_404(SQLLocation, domain=domain, location_id=loc_id)
    count = loc.get_descendants(include_self=True).count()
    return json_response({'count': count})
Beispiel #38
0
def submit_app_data_drilldown_form(request, domain):
    if json.loads(request.POST.get('is_deid')):
        raise Http404()

    model_type = request.POST.get('model_type')
    permissions = ExportsPermissionsManager(model_type, domain,
                                            request.couch_user)
    permissions.access_list_exports_or_404(is_deid=False)

    form_data = json.loads(request.POST.get('form_data'))
    is_daily_saved_export = json.loads(
        request.POST.get('is_daily_saved_export'))
    is_feed = json.loads(request.POST.get('is_feed'))
    is_odata = json.loads(request.POST.get('is_odata'))

    create_form = CreateExportTagForm(permissions.has_form_export_permissions,
                                      permissions.has_case_export_permissions,
                                      form_data)
    if not create_form.is_valid():
        return json_response({
            'success': False,
            'error': _("The form did not validate."),
        })

    from corehq.apps.export.views.new import (
        CreateNewCaseFeedView,
        CreateNewCustomCaseExportView,
        CreateNewCustomFormExportView,
        CreateNewDailySavedCaseExport,
        CreateNewDailySavedFormExport,
        CreateNewFormFeedView,
        CreateODataCaseFeedView,
        CreateODataFormFeedView,
    )

    if is_odata:
        if create_form.cleaned_data['model_type'] == "case":
            export_tag = create_form.cleaned_data['case_type']
            cls = CreateODataCaseFeedView
        else:
            export_tag = create_form.cleaned_data['form']
            cls = CreateODataFormFeedView
    elif is_daily_saved_export:
        if create_form.cleaned_data['model_type'] == "case":
            export_tag = create_form.cleaned_data['case_type']
            cls = CreateNewCaseFeedView if is_feed else CreateNewDailySavedCaseExport
        else:
            export_tag = create_form.cleaned_data['form']
            cls = CreateNewFormFeedView if is_feed else CreateNewDailySavedFormExport
    elif model_type == 'form':
        export_tag = create_form.cleaned_data['form']
        cls = CreateNewCustomFormExportView
    elif model_type == 'case':
        export_tag = create_form.cleaned_data['case_type']
        cls = CreateNewCustomCaseExportView

    url_params = '?export_tag="{}"'.format(export_tag)
    app_id = create_form.cleaned_data['application']
    if app_id != ApplicationDataRMIHelper.UNKNOWN_SOURCE:
        url_params += '&app_id={}'.format(app_id)

    return json_response({
        'success':
        True,
        'url':
        reverse(cls.urlname, args=[domain]) + url_params,
    })
Beispiel #39
0
def dashboard_tile(request, domain, slug):
    tile = _get_tile(request, slug)
    current_page = int(request.GET.get('currentPage', 1))
    items_per_page = int(request.GET.get('itemsPerPage', 5))
    items = list(tile.paginator.paginated_items(current_page, items_per_page))
    return json_response({'items': items})
Beispiel #40
0
def dashboard_tile_total(request, domain, slug):
    tile = _get_tile(request, slug)
    return json_response({'total': tile.paginator.total})
Beispiel #41
0
 def error(msg, code=400):
     return json_response({
         'status': 'error',
         'message': msg
     },
                          status_code=code)
Beispiel #42
0
def delete_request(request, domain):
    DomainRequest.objects.get(id=request.POST['id']).delete()
    return json_response({'status': 'ok'})
Beispiel #43
0
def filter_cases(request, domain, app_id, module_id):
    app = Application.get(app_id)
    module = app.get_module(module_id)
    delegation = request.GET.get('task-list') == 'true'
    auth_cookie = request.COOKIES.get('sessionid')

    suite_gen = SuiteGenerator(app)
    xpath = suite_gen.get_filter_xpath(module, delegation=delegation)
    extra_instances = [{
        'id': inst.id,
        'src': inst.src
    } for inst in suite_gen.get_instances_for_module(
        module, additional_xpaths=[xpath])]

    # touchforms doesn't like this to be escaped
    xpath = HTMLParser.HTMLParser().unescape(xpath)
    if delegation:
        case_type = DELEGATION_STUB_CASE_TYPE
    else:
        case_type = module.case_type

    if xpath:
        # if we need to do a custom filter, send it to touchforms for processing
        additional_filters = {
            "properties/case_type": case_type,
            "footprint": True
        }

        helper = SessionDataHelper(domain, request.couch_user)
        result = helper.filter_cases(xpath,
                                     additional_filters,
                                     DjangoAuth(auth_cookie),
                                     extra_instances=extra_instances)
        if result.get('status', None) == 'error':
            return HttpResponseServerError(
                result.get("message",
                           _("Something went wrong filtering your cases.")))

        case_ids = result.get("cases", [])
    else:
        # otherwise just use our built in api with the defaults
        case_ids = [
            res.id
            for res in get_filtered_cases(domain,
                                          status=CASE_STATUS_OPEN,
                                          case_type=case_type,
                                          user_id=request.couch_user._id,
                                          ids_only=True)
        ]

    cases = [
        CommCareCase.wrap(doc)
        for doc in iter_docs(CommCareCase.get_db(), case_ids)
    ]
    # refilter these because we might have accidentally included footprint cases
    # in the results from touchforms. this is a little hacky but the easiest
    # (quick) workaround. should be revisted when we optimize the case list.
    cases = filter(lambda c: c.type == case_type, cases)
    cases = [c.get_json(lite=True) for c in cases if c]
    parents = []
    if delegation:
        for case in cases:
            parent_id = case['indices']['parent']['case_id']
            parents.append(CommCareCase.get(parent_id))
        return json_response({'cases': cases, 'parents': parents})
    else:
        return json_response(cases)
Beispiel #44
0
def delete_invitation(request, domain):
    invitation_id = request.POST['id']
    invitation = Invitation.get(invitation_id)
    invitation.delete()
    return json_response({'status': 'ok'})
Beispiel #45
0
        assert case.domain == domain
        cases = [CaseAPIResult(id=case_id, couch_doc=case, id_only=ids_only)]
    else:
        filters = get_filters_from_request(request)
        status = api_closed_to_status(request.REQUEST.get('closed', 'false'))
        case_type = filters.get('properties/case_type', None)
        cases = get_filtered_cases(domain,
                                   status=status,
                                   case_type=case_type,
                                   user_id=user_id,
                                   filters=filters,
                                   footprint=footprint,
                                   ids_only=ids_only,
                                   strip_history=True,
                                   include_children=include_children)
    return json_response(cases)


@cloudcare_api
def filter_cases(request, domain, app_id, module_id):
    app = Application.get(app_id)
    module = app.get_module(module_id)
    delegation = request.GET.get('task-list') == 'true'
    auth_cookie = request.COOKIES.get('sessionid')

    suite_gen = SuiteGenerator(app)
    xpath = suite_gen.get_filter_xpath(module, delegation=delegation)
    extra_instances = [{
        'id': inst.id,
        'src': inst.src
    } for inst in suite_gen.get_instances_for_module(
Beispiel #46
0
def location_descendants_count(request, domain, loc_id):
    location = SQLLocation.objects.get(location_id=loc_id)
    if location.domain != domain:
        raise Http404()
    count = len(location.get_descendants(include_self=True))
    return json_response({'count': count})
Beispiel #47
0
 def json_response(self):
     """
         Intention: Not to be overridden in general.
         Renders the json version for the report, if available.
     """
     return json_response(self.json_dict)
Beispiel #48
0
def tables(request, domain):
    if request.method == 'GET':
        return json_response(
            [strip_json(x) for x in FixtureDataType.by_domain(domain)])
Beispiel #49
0
def filter_cases(request, domain, app_id, module_id, parent_id=None):
    app = Application.get(app_id)
    module = app.get_module(module_id)
    auth_cookie = request.COOKIES.get('sessionid')
    requires_parent_cases = string_to_boolean(
        request.GET.get('requires_parent_cases', 'false'))

    xpath = EntriesHelper.get_filter_xpath(module)
    instances = get_instances_for_module(app,
                                         module,
                                         additional_xpaths=[xpath])
    extra_instances = [{'id': inst.id, 'src': inst.src} for inst in instances]
    use_formplayer = toggles.USE_FORMPLAYER.enabled(domain)
    accessor = CaseAccessors(domain)

    # touchforms doesn't like this to be escaped
    xpath = HTMLParser.HTMLParser().unescape(xpath)
    case_type = module.case_type

    if xpath or should_use_sql_backend(domain):
        # if we need to do a custom filter, send it to touchforms for processing
        additional_filters = {
            "properties/case_type": case_type,
            "footprint": True
        }

        helper = BaseSessionDataHelper(domain, request.couch_user)
        result = helper.filter_cases(xpath,
                                     additional_filters,
                                     DjangoAuth(auth_cookie),
                                     extra_instances=extra_instances,
                                     use_formplayer=use_formplayer)
        if result.get('status', None) == 'error':
            code = result.get('code', 500)
            message = result.get(
                'message', _("Something went wrong filtering your cases."))
            if code == 500:
                notify_exception(None, message=message)
            return json_response(message, status_code=code)

        case_ids = result.get("cases", [])
    else:
        # otherwise just use our built in api with the defaults
        case_ids = [
            res.id for res in get_filtered_cases(
                domain,
                status=CASE_STATUS_OPEN,
                case_type=case_type,
                user_id=request.couch_user._id,
                footprint=True,
                ids_only=True,
            )
        ]

    cases = accessor.get_cases(case_ids)

    if parent_id:
        cases = filter(lambda c: c.parent and c.parent.case_id == parent_id,
                       cases)

    # refilter these because we might have accidentally included footprint cases
    # in the results from touchforms. this is a little hacky but the easiest
    # (quick) workaround. should be revisted when we optimize the case list.
    cases = filter(lambda c: c.type == case_type, cases)
    cases = [c.to_api_json(lite=True) for c in cases if c]

    response = {'cases': cases}
    if requires_parent_cases:
        # Subtract already fetched cases from parent list
        parent_ids = set(map(lambda c: c['indices']['parent']['case_id'], cases)) - \
            set(map(lambda c: c['case_id'], cases))
        parents = accessor.get_cases(list(parent_ids))
        parents = [c.to_api_json(lite=True) for c in parents]
        response.update({'parents': parents})

    return json_response(response)
Beispiel #50
0
def data_source_json(request, domain, config_id):
    config, _ = get_datasource_config_or_404(config_id, domain)
    del config._doc['_rev']
    return json_response(config)
Beispiel #51
0
def update_tables(request, domain, data_type_id=None):
    """
    receives a JSON-update patch like following
    {
        "_id":"0920fe1c6d4c846e17ee33e2177b36d6",
        "tag":"growth",
        "view_link":"/a/gsid/fixtures/view_lookup_tables/?table_id:0920fe1c6d4c846e17ee33e2177b36d6",
        "is_global":false,
        "fields":{"genderr":{"update":"gender"},"grade":{}}
    }
    """
    if data_type_id:
        try:
            data_type = FixtureDataType.get(data_type_id)
        except ResourceNotFound:
            raise Http404()

        if data_type.domain != domain:
            raise Http404()

        if request.method == 'GET':
            return json_response(strip_json(data_type))

        elif request.method == 'DELETE':
            with CouchTransaction() as transaction:
                data_type.recursive_delete(transaction)
            clear_fixture_cache(domain)
            return json_response({})
        elif not request.method == 'PUT':
            return HttpResponseBadRequest()

    if request.method == 'POST' or request.method == "PUT":
        fields_update = _to_kwargs(request)
        fields_patches = fields_update["fields"]
        data_tag = fields_update["tag"]
        is_global = fields_update["is_global"]
        description = fields_update["description"]

        # validate tag and fields
        validation_errors = []
        if is_identifier_invalid("{}_list".format(data_tag)):
            validation_errors.append(data_tag)
        for field_name, options in fields_update['fields'].items():
            method = list(options.keys())
            if 'update' in method:
                field_name = options['update']
            if is_identifier_invalid(field_name) and 'remove' not in method:
                validation_errors.append(field_name)
        validation_errors = [
            _("\"%s\" cannot include special characters, begin or end with a space, "
              "or begin with \"xml\" or a number") % e
            for e in validation_errors
        ]
        if len(data_tag) < 1 or len(data_tag) > 31:
            validation_errors.append(
                _("Table ID must be between 1 and 31 characters."))

        if validation_errors:
            return json_response({
                'validation_errors':
                validation_errors,
                'error_msg':
                _("Could not update table because field names were not "
                  "correctly formatted"),
            })

        with CouchTransaction() as transaction:
            if data_type_id:
                data_type = _update_types(fields_patches, domain, data_type_id,
                                          data_tag, is_global, description,
                                          transaction)
                _update_items(fields_patches, domain, data_type_id,
                              transaction)
            else:
                if FixtureDataType.fixture_tag_exists(domain, data_tag):
                    return HttpResponseBadRequest("DuplicateFixture")
                else:
                    data_type = _create_types(fields_patches, domain, data_tag,
                                              is_global, description,
                                              transaction)
        clear_fixture_cache(domain)
        return json_response(strip_json(data_type))
Beispiel #52
0
                instance_id).get_xml()
        except XFormNotFound:
            raise Http404()

    session_extras = {'session_name': session_name, 'app_id': app._id}
    session_extras.update(
        get_cloudcare_session_data(domain, form, request.couch_user))

    delegation = request.GET.get('task-list') == 'true'
    session_helper = CaseSessionDataHelper(domain,
                                           request.couch_user,
                                           case_id,
                                           app,
                                           form,
                                           delegation=delegation)
    return json_response(
        session_helper.get_full_context(root_context, session_extras))


cloudcare_api = login_or_digest_ex(allow_cc_users=True)


class ReadableQuestions(View):

    urlname = 'readable_questions'

    @csrf_exempt
    @method_decorator(cloudcare_api)
    def dispatch(self, request, *args, **kwargs):
        return super(ReadableQuestions, self).dispatch(request, *args,
                                                       **kwargs)
Beispiel #53
0
def fixture_metadata(request, domain):
    """
    Returns list of fixtures and metadata needed for itemsets in vellum
    """
    return json_response(item_lists_by_domain(domain))
Beispiel #54
0
def get_app_api(request, domain, app_id):
    return json_response(look_up_app_json(domain, app_id))
Beispiel #55
0
def report_source_json(request, domain, report_id):
    config = get_document_or_404(ReportConfiguration, domain, report_id)
    del config._doc['_rev']
    return json_response(config)
Beispiel #56
0
def edit_module_detail_screens(request, domain, app_id, module_unique_id):
    """
    Overwrite module case details. Only overwrites components that have been
    provided in the request. Components are short, long, filter, parent_select,
    fixture_select and sort_elements.
    """
    params = json_request(request.POST)
    detail_type = params.get('type')
    short = params.get('short', None)
    long_ = params.get('long', None)
    tabs = params.get('tabs', None)
    filter = params.get('filter', ())
    custom_xml = params.get('custom_xml', None)
    parent_select = params.get('parent_select', None)
    fixture_select = params.get('fixture_select', None)
    sort_elements = params.get('sort_elements', None)
    persist_case_context = params.get('persistCaseContext', None)
    persistent_case_context_xml = params.get('persistentCaseContextXML', None)
    use_case_tiles = params.get('useCaseTiles', None)
    persist_tile_on_forms = params.get("persistTileOnForms", None)
    persistent_case_tile_from_module = params.get("persistentCaseTileFromModule", None)
    pull_down_tile = params.get("enableTilePullDown", None)
    sort_nodeset_columns = params.get("sortNodesetColumns", None)
    print_template = params.get('printTemplate', None)
    case_list_lookup = params.get("case_list_lookup", None)
    search_properties = params.get("search_properties")
    custom_variables = {
        'short': params.get("short_custom_variables", None),
        'long': params.get("long_custom_variables", None)
    }

    app = get_app(domain, app_id)

    try:
        module = app.get_module_by_unique_id(module_unique_id)
    except ModuleNotFoundException:
        # temporary fallback
        module = app.get_module(module_unique_id)

    if detail_type == 'case':
        detail = module.case_details
    else:
        try:
            detail = getattr(module, '{0}_details'.format(detail_type))
        except AttributeError:
            return HttpResponseBadRequest("Unknown detail type '%s'" % detail_type)

    lang = request.COOKIES.get('lang', app.langs[0])
    if short is not None:
        detail.short.columns = list(map(DetailColumn.from_json, short))
        if persist_case_context is not None:
            detail.short.persist_case_context = persist_case_context
            detail.short.persistent_case_context_xml = persistent_case_context_xml
        if use_case_tiles is not None:
            detail.short.use_case_tiles = use_case_tiles
        if persist_tile_on_forms is not None:
            detail.short.persist_tile_on_forms = persist_tile_on_forms
        if persistent_case_tile_from_module is not None:
            detail.short.persistent_case_tile_from_module = persistent_case_tile_from_module
        if pull_down_tile is not None:
            detail.short.pull_down_tile = pull_down_tile
        if case_list_lookup is not None:
            _save_case_list_lookup_params(detail.short, case_list_lookup, lang)

    if long_ is not None:
        detail.long.columns = list(map(DetailColumn.from_json, long_))
        if tabs is not None:
            detail.long.tabs = list(map(DetailTab.wrap, tabs))
        if print_template is not None:
            detail.long.print_template = print_template
    if filter != ():
        # Note that we use the empty tuple as the sentinel because a filter
        # value of None represents clearing the filter.
        detail.short.filter = filter
    if custom_xml is not None:
        detail.short.custom_xml = custom_xml

    if custom_variables['short'] is not None:
        try:
            etree.fromstring("<variables>{}</variables>".format(custom_variables['short']))
        except etree.XMLSyntaxError as error:
            return HttpResponseBadRequest(
                "There was an issue with your custom variables: {}".format(error.message)
            )
        detail.short.custom_variables = custom_variables['short']

    if custom_variables['long'] is not None:
        try:
            etree.fromstring("<variables>{}</variables>".format(custom_variables['long']))
        except etree.XMLSyntaxError as error:
            return HttpResponseBadRequest(
                "There was an issue with your custom variables: {}".format(error.message)
            )
        detail.long.custom_variables = custom_variables['long']

    if sort_nodeset_columns is not None:
        detail.long.sort_nodeset_columns = sort_nodeset_columns

    if sort_elements is not None:
        # Attempt to map new elements to old so we don't lose translations
        # Imperfect because the same field may be used multiple times, or user may change field
        old_elements_by_field = {e['field']: e for e in detail.short.sort_elements}

        detail.short.sort_elements = []
        for sort_element in sort_elements:
            item = SortElement()
            item.field = sort_element['field']
            item.type = sort_element['type']
            item.direction = sort_element['direction']
            item.blanks = sort_element['blanks']
            if item.field in old_elements_by_field:
                item.display = old_elements_by_field[item.field].display
            item.display[lang] = sort_element['display']
            if toggles.SORT_CALCULATION_IN_CASE_LIST.enabled(domain):
                item.sort_calculation = sort_element['sort_calculation']
            else:
                item.sort_calculation = ""
            detail.short.sort_elements.append(item)
    if parent_select is not None:
        module.parent_select = ParentSelect.wrap(parent_select)
        if module_case_hierarchy_has_circular_reference(module):
            return HttpResponseBadRequest(_("The case hierarchy contains a circular reference."))
    if fixture_select is not None:
        module.fixture_select = FixtureSelect.wrap(fixture_select)
    if search_properties is not None:
        if (
                search_properties.get('properties') is not None
                or search_properties.get('default_properties') is not None
        ):
            module.search_config = CaseSearch(
                properties=[
                    CaseSearchProperty.wrap(p)
                    for p in _update_search_properties(
                        module,
                        search_properties.get('properties'), lang
                    )
                ],
                relevant=(
                    search_properties.get('relevant')
                    if search_properties.get('relevant') is not None
                    else CLAIM_DEFAULT_RELEVANT_CONDITION
                ),
                include_closed=bool(search_properties.get('include_closed')),
                search_button_display_condition=search_properties.get('search_button_display_condition', ""),
                blacklisted_owner_ids_expression=search_properties.get('blacklisted_owner_ids_expression', ""),
                default_properties=[
                    DefaultCaseSearchProperty.wrap(p)
                    for p in search_properties.get('default_properties')
                ]
            )

    resp = {}
    app.save(resp)
    return json_response(resp)
Beispiel #57
0
def download_item_lists(request, domain, html_response=False):
    """
        Is used to serve excel_download and html_view for view_lookup_tables
    """
    table_ids = request.GET.getlist("table_id")
    if table_ids and table_ids[0]:
        try:
            data_types_view = [
                FixtureDataType.get(id)
                for id in request.GET.getlist("table_id")
            ]
        except ResourceNotFound as Ex:
            if html_response:
                messages.info(
                    request,
                    _("Sorry, we couldn't find that table. If you think this is a mistake please report an issue."
                      ))
                raise
            data_types_view = FixtureDataType.by_domain(domain)
    else:
        data_types_view = FixtureDataType.by_domain(domain)

    if html_response:
        data_types_view = list(data_types_view)[0:1]
    # book-keeping data from view_results for repeated use
    data_types_book = []
    data_items_book_by_type = {}
    item_helpers_by_type = {}
    """
        Contains all excel sheets in following format
        excel_sheets = {
            "types": {
                "headers": [],
                "rows": [(row), (row), (row)]
            }
            "next-sheet": {
                "headers": [],
                "rows": [(row), (row), (row)]
            },
            ...
        }
    """
    excel_sheets = {}

    def empty_padding_list(length):
        return ["" for x in range(0, length)]

    max_fields = 0
    """
        - Helper to generate headers like "field 2: property 1"
        - Captures max_num_of_properties for any field of any type at the list-index.
        Example values:
            [0, 1] -> "field 2: property 1" (first-field has zero-props, second has 1 property)
            [1, 1] -> "field 1: property 1" (first-field has 1 property, second has 1 property)
            [0, 2] -> "field 2: property 1", "field 2: property 2"
    """
    field_prop_count = []
    """
        captures all possible 'field-property' values for each data-type
        Example value
          {u'clinics': {'field 2 : property 1': u'lang'}, u'growth_chart': {'field 2 : property 2': u'maxWeight'}}
    """
    type_field_properties = {}
    get_field_prop_format = lambda x, y: "field " + str(
        x) + " : property " + str(y)
    for data_type in data_types_view:
        # Helpers to generate 'types' sheet
        type_field_properties[data_type.tag] = {}
        data_types_book.append(data_type)
        if len(data_type.fields) > max_fields:
            max_fields = len(data_type.fields)
        for index, field in enumerate(data_type.fields):
            if len(field_prop_count) <= index:
                field_prop_count.append(len(field.properties))
            elif field_prop_count[index] <= len(field.properties):
                field_prop_count[index] = len(field.properties)
            if len(field.properties) > 0:
                for prop_index, property in enumerate(field.properties):
                    prop_key = get_field_prop_format(index + 1, prop_index + 1)
                    type_field_properties[data_type.tag][prop_key] = property
        # Helpers to generate item-sheets
        data_items_book_by_type[data_type.tag] = []
        max_users = 0
        max_groups = 0
        max_field_prop_combos = {
            field_name: 0
            for field_name in data_type.fields_without_attributes
        }
        for item_row in FixtureDataItem.by_data_type(domain, data_type.get_id):
            data_items_book_by_type[data_type.tag].append(item_row)
            group_len = len(item_row.groups)
            max_groups = group_len if group_len > max_groups else max_groups
            user_len = len(item_row.users)
            max_users = user_len if user_len > max_users else max_users
            for field_key in item_row.fields:
                max_combos = max_field_prop_combos[field_key]
                cur_combo_len = len(item_row.fields[field_key].field_list)
                max_combos = cur_combo_len if cur_combo_len > max_combos else max_combos
                max_field_prop_combos[field_key] = max_combos
        item_helpers = {
            "max_users": max_users,
            "max_groups": max_groups,
            "max_field_prop_combos": max_field_prop_combos,
        }
        item_helpers_by_type[data_type.tag] = item_helpers

    # Prepare 'types' sheet data
    types_sheet = {"headers": [], "rows": []}
    types_sheet["headers"] = [DELETE_HEADER, "table_id", 'is_global?']
    types_sheet["headers"].extend(
        ["field %d" % x for x in range(1, max_fields + 1)])
    field_prop_headers = []
    for field_num, prop_num in enumerate(field_prop_count):
        if prop_num > 0:
            for c in range(0, prop_num):
                prop_key = get_field_prop_format(field_num + 1, c + 1)
                field_prop_headers.append(prop_key)
                types_sheet["headers"].append(prop_key)

    for data_type in data_types_book:
        common_vals = ["N", data_type.tag, yesno(data_type.is_global)]
        field_vals = [
            field.field_name for field in data_type.fields
        ] + empty_padding_list(max_fields - len(data_type.fields))
        prop_vals = []
        if type_field_properties.has_key(data_type.tag):
            props = type_field_properties.get(data_type.tag)
            prop_vals.extend(
                [props.get(key, "") for key in field_prop_headers])
        row = tuple(common_vals[2 if html_response else 0:] + field_vals +
                    prop_vals)
        types_sheet["rows"].append(row)

    types_sheet["rows"] = tuple(types_sheet["rows"])
    types_sheet["headers"] = tuple(types_sheet["headers"])
    excel_sheets["types"] = types_sheet

    # Prepare 'items' sheet data for each data-type
    for data_type in data_types_book:
        item_sheet = {"headers": [], "rows": []}
        item_helpers = item_helpers_by_type[data_type.tag]
        max_users = item_helpers["max_users"]
        max_groups = item_helpers["max_groups"]
        max_field_prop_combos = item_helpers["max_field_prop_combos"]
        common_headers = ["UID", DELETE_HEADER]
        user_headers = ["user %d" % x for x in range(1, max_users + 1)]
        group_headers = ["group %d" % x for x in range(1, max_groups + 1)]
        field_headers = []
        for field in data_type.fields:
            if len(field.properties) == 0:
                field_headers.append("field: " + field.field_name)
            else:
                prop_headers = []
                for x in range(1, max_field_prop_combos[field.field_name] + 1):
                    for property in field.properties:
                        prop_headers.append("%(name)s: %(prop)s %(count)s" % {
                            "name": field.field_name,
                            "prop": property,
                            "count": x
                        })
                    prop_headers.append("field: %(name)s %(count)s" % {
                        "name": field.field_name,
                        "count": x
                    })
                field_headers.extend(prop_headers)
        item_sheet["headers"] = tuple(
            common_headers[2 if html_response else 0:] + field_headers +
            user_headers + group_headers)
        excel_sheets[data_type.tag] = item_sheet
        for item_row in data_items_book_by_type[data_type.tag]:
            common_vals = [str(_id_from_doc(item_row)), "N"]
            user_vals = [
                user.raw_username for user in item_row.users
            ] + empty_padding_list(max_users - len(item_row.users))
            group_vals = [
                group.name for group in item_row.groups
            ] + empty_padding_list(max_groups - len(item_row.groups))
            field_vals = []
            for field in data_type.fields:
                if len(field.properties) == 0:
                    if any(item_row.fields.get(field.field_name).field_list):
                        value = item_row.fields.get(
                            field.field_name).field_list[0].field_value
                    else:
                        value = ""
                    field_vals.append(value)
                else:
                    field_prop_vals = []
                    cur_combo_count = len(
                        item_row.fields.get(field.field_name).field_list)
                    cur_prop_count = len(field.properties)
                    for count, field_prop_combo in enumerate(
                            item_row.fields.get(field.field_name).field_list):
                        for property in field.properties:
                            field_prop_vals.append(
                                field_prop_combo.properties.get(
                                    property, None) or "")
                        field_prop_vals.append(field_prop_combo.field_value)
                    padding_list_len = (
                        max_field_prop_combos[field.field_name] -
                        cur_combo_count) * (cur_prop_count + 1)
                    field_prop_vals.extend(
                        empty_padding_list(padding_list_len))
                    # import pdb; pdb.set_trace();
                    field_vals.extend(field_prop_vals)
            row = tuple(common_vals[2 if html_response else 0:] + field_vals +
                        user_vals + group_vals)
            item_sheet["rows"].append(row)
        item_sheet["rows"] = tuple(item_sheet["rows"])
        excel_sheets[data_type.tag] = item_sheet

    if html_response:
        return excel_sheets

    header_groups = [("types", excel_sheets["types"]["headers"])]
    value_groups = [("types", excel_sheets["types"]["rows"])]
    for data_type in data_types_book:
        header_groups.append(
            (data_type.tag, excel_sheets[data_type.tag]["headers"]))
        value_groups.append(
            (data_type.tag, excel_sheets[data_type.tag]["rows"]))

    fd, path = tempfile.mkstemp()
    with os.fdopen(fd, 'w') as temp:
        export_raw(tuple(header_groups), tuple(value_groups), temp)
    format = Format.XLS_2007

    fl = open(path, 'r')
    fileref = expose_download(
        fl.read(),
        60 * 10,
        mimetype=Format.from_format(format).mimetype,
        content_disposition='attachment; filename="%s_fixtures.xlsx"' % domain,
    )
    return json_response({"download_id": fileref.download_id})
Beispiel #58
0
def get_sessions(request, domain):
    # is it ok to pull user from the request? other api calls seem to have an explicit 'user' param
    skip = request.GET.get('skip') or 0
    limit = request.GET.get('limit') or 10
    return json_response(
        get_open_form_sessions(request.user, skip=skip, limit=limit))
Beispiel #59
0
def delete_invitation(request, domain):
    uuid = request.POST['uuid']
    invitation = Invitation.objects.get(uuid=uuid)
    invitation.delete()
    return json_response({'status': 'ok'})
Beispiel #60
0
def _edit_form_attr(request, domain, app_id, form_unique_id, attr):
    """
    Called to edit any (supported) form attribute, given by attr

    """

    ajax = json.loads(request.POST.get('ajax', 'true'))
    resp = {}

    app = get_app(domain, app_id)
    try:
        form = app.get_form(form_unique_id)
    except FormNotFoundException as e:
        if ajax:
            return HttpResponseBadRequest(six.text_type(e))
        else:
            messages.error(request,
                           _("There was an error saving, please try again!"))
            return back_to_main(request, domain, app_id=app_id)
    lang = request.COOKIES.get('lang', app.langs[0])

    def should_edit(attribute):
        return attribute in request.POST

    if should_edit("name"):
        name = request.POST['name']
        form.name[lang] = name
        if not form.form_type == "shadow_form":
            xform = form.wrapped_xform()
            if xform.exists():
                xform.set_name(name)
                save_xform(app, form, xform.render())
        resp['update'] = {
            '.variable-form_name': trans(form.name, [lang], use_delim=False)
        }
    if should_edit('comment'):
        form.comment = request.POST['comment']
    if should_edit("xform") or "xform" in request.FILES:
        try:
            # support FILES for upload and POST for ajax post from Vellum
            try:
                xform = request.FILES.get('xform').read()
            except Exception:
                xform = request.POST.get('xform')
            else:
                try:
                    xform = six.text_type(xform, encoding="utf-8")
                except Exception:
                    raise Exception(
                        "Error uploading form: Please make sure your form is encoded in UTF-8"
                    )
            if request.POST.get('cleanup', False):
                try:
                    # First, we strip all newlines and reformat the DOM.
                    px = parseString(xform.replace('\r\n', '')).toprettyxml()
                    # Then we remove excess newlines from the DOM output.
                    text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</',
                                         re.DOTALL)
                    prettyXml = text_re.sub('>\g<1></', px)
                    xform = prettyXml
                except Exception:
                    pass
            if xform:
                save_xform(app, form, xform)
            else:
                raise Exception("You didn't select a form to upload")
        except Exception as e:
            if ajax:
                return HttpResponseBadRequest(six.text_type(e))
            else:
                messages.error(request, six.text_type(e))
    if should_edit("references") or should_edit("case_references"):
        form.case_references = _get_case_references(request.POST)
    if should_edit("show_count"):
        show_count = request.POST['show_count']
        form.show_count = True if show_count == "True" else False
    if should_edit("put_in_root"):
        put_in_root = request.POST['put_in_root']
        form.put_in_root = True if put_in_root == "True" else False
    if should_edit('form_filter'):
        form.form_filter = request.POST['form_filter']
    if should_edit('post_form_workflow'):
        form.post_form_workflow = request.POST['post_form_workflow']
    if should_edit('auto_gps_capture'):
        form.auto_gps_capture = request.POST['auto_gps_capture'] == 'true'
    if should_edit('no_vellum'):
        form.no_vellum = request.POST['no_vellum'] == 'true'
    if (should_edit("form_links_xpath_expressions")
            and should_edit("form_links_form_ids")
            and toggles.FORM_LINK_WORKFLOW.enabled(domain)):
        form_links = zip(
            request.POST.getlist('form_links_xpath_expressions'),
            request.POST.getlist('form_links_form_ids'),
            [
                json.loads(datum_json) if datum_json else []
                for datum_json in request.POST.getlist('datums_json')
            ],
        )
        form.form_links = [
            FormLink(xpath=link[0],
                     form_id=link[1],
                     datums=[
                         FormDatum(name=datum['name'], xpath=datum['xpath'])
                         for datum in link[2]
                     ]) for link in form_links
        ]

    if should_edit('post_form_workflow_fallback'):
        form.post_form_workflow_fallback = request.POST.get(
            'post_form_workflow_fallback')

    if should_edit('custom_instances'):
        instances = json.loads(request.POST.get('custom_instances'))
        try:  # validate that custom instances can be added into the XML
            for instance in instances:
                etree.fromstring("<instance id='{}' src='{}' />".format(
                    instance.get('instanceId'), instance.get('instancePath')))
        except etree.XMLSyntaxError as error:
            return json_response(
                {
                    'message':
                    _("There was an issue with your custom instances: {}").
                    format(error.message)
                },
                status_code=400)

        form.custom_instances = [
            CustomInstance(
                instance_id=instance.get("instanceId"),
                instance_path=instance.get("instancePath"),
            ) for instance in instances
        ]
    if should_edit("shadow_parent"):
        form.shadow_parent_form_id = request.POST['shadow_parent']

    if should_edit("custom_icon_form"):
        error_message = handle_custom_icon_edits(request, form, lang)
        if error_message:
            return json_response({'message': error_message}, status_code=400)
    handle_media_edits(request, form, should_edit, resp, lang)

    app.save(resp)
    notify_form_changed(domain, request.couch_user, app_id, form_unique_id)
    if ajax:
        return HttpResponse(json.dumps(resp))
    else:
        return back_to_main(request,
                            domain,
                            app_id=app_id,
                            form_unique_id=form_unique_id)