Ejemplo n.º 1
0
 def validate_spec(self, spec):
     value = spec.get(self.column_id)
     if isinstance(value, str):
         try:
             string_to_boolean(value) if value else None
         except ValueError:
             return self.error_message
Ejemplo n.º 2
0
 def validate_spec(self, spec):
     is_active = spec.get('is_active')
     if isinstance(is_active, str):
         try:
             string_to_boolean(is_active) if is_active else None
         except ValueError:
             return self.error_message
Ejemplo n.º 3
0
def get_cases(request, domain):
    request_params = request.GET

    if request.couch_user.is_commcare_user():
        user_id = request.couch_user.get_id
    else:
        user_id = request_params.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_params.get("ids_only", "false"))
    case_id = request_params.get("case_id", "")
    footprint = string_to_boolean(request_params.get("footprint", "false"))
    accessor = CaseAccessors(domain)

    if toggles.HSPH_HACK.enabled(domain):
        hsph_case_id = request_params.get('hsph_hack', None)
        if hsph_case_id != 'None' and hsph_case_id and user_id:
            case = accessor.get_case(hsph_case_id)
            usercase_id = CommCareUser.get_by_user_id(
                user_id).get_usercase_id()
            usercase = accessor.get_case(usercase_id) if usercase_id else None
            return json_response(
                map(
                    lambda case: CaseAPIResult(
                        id=case['_id'], couch_doc=case, id_only=ids_only),
                    filter(None, [case, case.parent, usercase])))
Ejemplo n.º 4
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)]
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
def export_data(req, domain):
    """
    Download all data for a couchdbkit model
    """
    try:
        export_tag = json.loads(req.GET.get("export_tag", "null") or "null")
    except ValueError:
        return HttpResponseBadRequest()

    group, users = util.get_group_params(domain, **json_request(req.GET))
    include_errors = string_to_boolean(req.GET.get("include_errors", False))

    kwargs = {
        "format": req.GET.get("format", Format.XLS_2007),
        "previous_export_id": req.GET.get("previous_export", None),
        "filename": export_tag,
        "use_cache": string_to_boolean(req.GET.get("use_cache", "True")),
        "max_column_size": int(req.GET.get("max_column_size", 2000)),
        "separator": req.GET.get("separator", "|")
    }

    user_filter, _ = UserTypeFilter.get_user_filter(req)

    if user_filter:
        filtered_users = users_matching_filter(domain, user_filter)

        def _ufilter(user):
            try:
                return user['form']['meta']['userID'] in filtered_users
            except KeyError:
                return False

        filter = _ufilter
    else:
        filter = SerializableFunction(util.group_filter, group=group)

    errors_filter = instances if not include_errors else None

    kwargs['filter'] = couchexport.util.intersect_functions(
        filter, errors_filter)
    if kwargs['format'] == 'raw':
        resp = export_raw_data([domain, export_tag], filename=export_tag)
    else:
        try:
            resp = export_data_shared([domain, export_tag], **kwargs)
        except CouchExportException as e:
            return HttpResponseBadRequest(e)
    if resp:
        return resp
    else:
        messages.error(
            req,
            "Sorry, there was no data found for the tag '%s'." % export_tag)
        next = req.GET.get("next", "")
        if not next:
            next = export.ExcelExportReport.get_url(domain=domain)
        return HttpResponseRedirect(next)
Ejemplo n.º 7
0
    def handle(self, *args, **options):
        direction = BOTH if len(args) < 1 else args[0].strip().lower()
        if not direction in SYNC_DIRECTIONS:
            raise CommandError(
                '"%s" is not a valid sync direction.  It must be one of %s'
                % (direction, ", ".join(('"%s"' % dir for dir in SYNC_DIRECTIONS)))
            )

        continuous = False if len(args) < 2 else string_to_boolean(args[1].strip())
        cancel = False if len(args) < 3 else string_to_boolean(args[1].strip())
        do_sync(direction, continuous, cancel)
Ejemplo n.º 8
0
def export_data(req, domain):
    """
    Download all data for a couchdbkit model
    """
    try:
        export_tag = json.loads(req.GET.get("export_tag", "null") or "null")
    except ValueError:
        return HttpResponseBadRequest()

    group, users = util.get_group_params(domain, **json_request(req.GET))
    include_errors = string_to_boolean(req.GET.get("include_errors", False))

    kwargs = {
        "format": req.GET.get("format", Format.XLS_2007),
        "previous_export_id": req.GET.get("previous_export", None),
        "filename": export_tag,
        "use_cache": string_to_boolean(req.GET.get("use_cache", "True")),
        "max_column_size": int(req.GET.get("max_column_size", 2000)),
        "separator": req.GET.get("separator", "|"),
    }

    user_filter, _ = UserTypeFilter.get_user_filter(req)

    if user_filter:
        filtered_users = users_matching_filter(domain, user_filter)

        def _ufilter(user):
            try:
                return user["form"]["meta"]["userID"] in filtered_users
            except KeyError:
                return False

        filter = _ufilter
    else:
        filter = SerializableFunction(util.group_filter, group=group)

    errors_filter = instances if not include_errors else None

    kwargs["filter"] = couchexport.util.intersect_functions(filter, errors_filter)
    if kwargs["format"] == "raw":
        resp = export_raw_data([domain, export_tag], filename=export_tag)
    else:
        try:
            resp = export_data_shared([domain, export_tag], **kwargs)
        except CouchExportException as e:
            return HttpResponseBadRequest(e)
    if resp:
        return resp
    else:
        messages.error(req, "Sorry, there was no data found for the tag '%s'." % export_tag)
        next = req.GET.get("next", "")
        if not next:
            next = export.ExcelExportReport.get_url(domain=domain)
        return HttpResponseRedirect(next)
Ejemplo n.º 9
0
def get_cases_skip_arg(request, domain):
    """
    When this function returns True, skippable_quickcache will not go to the cache for the result. By default,
    if neither of these params are passed into the function, nothing will be cached. Cache will always be
    skipped if ids_only is false.

    The caching is mainly a hack for touchforms to respond more quickly. Touchforms makes repeated requests to
    get the list of case_ids associated with a user.
    """
    request_params = request.GET
    return (not string_to_boolean(request_params.get('use_cache', 'false'))
            or not string_to_boolean(request_params.get('ids_only', 'false')))
Ejemplo n.º 10
0
def export_data(req, domain):
    """
    Download all data for a couchdbkit model
    """
    try:
        export_tag = json.loads(req.GET.get("export_tag", "null") or "null")
    except ValueError:
        return HttpResponseBadRequest()

    group, users = util.get_group_params(domain, **json_request(req.GET))
    include_errors = string_to_boolean(req.GET.get("include_errors", False))

    kwargs = {"format": req.GET.get("format", Format.XLS_2007),
              "previous_export_id": req.GET.get("previous_export", None),
              "filename": export_tag,
              "use_cache": string_to_boolean(req.GET.get("use_cache", "True")),
              "max_column_size": int(req.GET.get("max_column_size", 2000)),
              "separator": req.GET.get("separator", "|")}

    user_filter, _ = FilterUsersField.get_user_filter(req)

    if user_filter:
        users_matching_filter = map(lambda x: x.get('user_id'), get_all_users_by_domain(domain,
            user_filter=user_filter, simplified=True))
        def _ufilter(user):
            try:
                return user['form']['meta']['userID'] in users_matching_filter
            except KeyError:
                return False
        filter = _ufilter
    else:
        filter = SerializableFunction(util.group_filter, group=group)

    errors_filter = instances if not include_errors else None

    kwargs['filter'] = couchexport.util.intersect_functions(filter, errors_filter)

    if kwargs['format'] == 'raw':
        resp = export_raw_data([domain, export_tag], filename=export_tag)
    else:
        try:
            resp = export_data_shared([domain,export_tag], **kwargs)
        except UnsupportedExportFormat as e:
            return HttpResponseBadRequest(e)
    if resp:
        return resp
    else:
        messages.error(req, "Sorry, there was no data found for the tag '%s'." % export_tag)
        next = req.GET.get("next", "")
        if not next:
            next = export.ExcelExportReport.get_url(domain)
        return HttpResponseRedirect(next)
Ejemplo n.º 11
0
def get_cases_skip_arg(request, domain):
    """
    When this function returns True, skippable_quickcache will not go to the cache for the result. By default,
    if neither of these params are passed into the function, nothing will be cached. Cache will always be
    skipped if ids_only is false.

    The caching is mainly a hack for touchforms to respond more quickly. Touchforms makes repeated requests to
    get the list of case_ids associated with a user.
    """
    if not toggles.CLOUDCARE_CACHE.enabled(domain):
        return True
    return (not string_to_boolean(request.REQUEST.get('use_cache', 'false')) or
        not string_to_boolean(request.REQUEST.get('ids_only', 'false')))
Ejemplo n.º 12
0
 def __init__(self, tests, runner):
     reuse_db = (CmdLineParametersPlugin.get('reusedb')
                 or string_to_boolean(os.environ.get("REUSE_DB") or "0"))
     self.reuse_db = reuse_db
     self.skip_setup_for_reuse_db = reuse_db and reuse_db != "reset"
     self.skip_teardown_for_reuse_db = reuse_db and reuse_db != "teardown"
     super(HqdbContext, self).__init__(tests, runner)
Ejemplo n.º 13
0
 def filter_set(self):
     """
     Whether a report has any filters set. Based on whether or not there 
     is a query string. This gets carried to additional asynchronous calls
     """
     return string_to_boolean(self.request.GET.get("filterSet")) \
         if "filterSet" in self.request.GET else bool(self.request.META.get('QUERY_STRING'))
Ejemplo n.º 14
0
 def recipients_filter(self, user):
     roles = user.user_data.get('role', [])
     if not roles:
         return False
     needs_reminders = string_to_boolean(user.user_data.get('needs_reminders', "False"))
     return any([role != IN_CHARGE_ROLE for role in user.user_data.get('role', [])]) and \
         needs_reminders and user.location_id
Ejemplo n.º 15
0
 def __init__(self, tests, runner):
     reuse_db = (CmdLineParametersPlugin.get('reusedb')
                 or string_to_boolean(os.environ.get("REUSE_DB") or "0"))
     self.reuse_db = reuse_db
     self.skip_setup_for_reuse_db = reuse_db and reuse_db != "reset"
     self.skip_teardown_for_reuse_db = reuse_db and reuse_db != "teardown"
     super(HqdbContext, self).__init__(tests, runner)
Ejemplo n.º 16
0
def api_send_sms(request, domain):
    """
    An API to send SMS.
    Expected post parameters:
        phone_number - the phone number to send to
        contact_id - the _id of a contact to send to (overrides phone_number)
        text - the text of the message
        backend_id - the name of the MobileBackend to use while sending
    """
    if request.method == "POST":
        phone_number = request.POST.get("phone_number", None)
        contact_id = request.POST.get("contact_id", None)
        text = request.POST.get("text", None)
        backend_id = request.POST.get("backend_id", None)
        chat = request.POST.get("chat", None)

        if (phone_number is None and contact_id is None) or (text is None):
            return HttpResponseBadRequest("Not enough arguments.")

        vn = None
        if contact_id is not None:
            try:
                contact = get_contact(contact_id)
                assert contact is not None
                assert contact.domain == domain
            except Exception:
                return HttpResponseBadRequest("Contact not found.")
            try:
                vn = contact.get_verified_number()
                assert vn is not None
                phone_number = vn.phone_number
            except Exception:
                return HttpResponseBadRequest("Contact has no phone number.")

        try:
            chat_workflow = string_to_boolean(chat)
        except Exception:
            chat_workflow = False

        if chat_workflow:
            chat_user_id = request.couch_user._id
        else:
            chat_user_id = None

        metadata = MessageMetadata(
            chat_user_id=chat_user_id
        )
        if backend_id is not None:
            success = send_sms_with_backend_name(domain, phone_number, text, backend_id, metadata)
        elif vn is not None:
            success = send_sms_to_verified_number(vn, text, metadata)
        else:
            success = send_sms(domain, None, phone_number, text, metadata)

        if success:
            return HttpResponse("OK")
        else:
            return HttpResponse("ERROR")
    else:
        return HttpResponseBadRequest("POST Expected.")
Ejemplo n.º 17
0
def app_list(request, domain, urlPath):
    preview = string_to_boolean(request.REQUEST.get("preview", "false"))
    language = request.couch_user.language or "en"
    
    def _app_latest_build_json(app_id):
        build = ApplicationBase.view('app_manager/saved_app',
                                     startkey=[domain, app["_id"], {}],
                                     endkey=[domain, app["_id"]],
                                     descending=True,
                                     limit=1).one()
        return build._doc if build else None
                                     
    if not preview:
        apps = get_cloudcare_apps(domain)
        # replace the apps with the last build of each app
        apps = [_app_latest_build_json(app["_id"])for app in apps]
    
    else:
        apps = ApplicationBase.view('app_manager/applications_brief', startkey=[domain], endkey=[domain, {}])
        apps = [app._doc for app in apps if app and app.application_version == "2.0"]
    
    # trim out empty apps
    apps = filter(lambda app: app, apps)
    return render_to_response(request, "cloudcare/cloudcare_home.html", 
                              {"domain": domain,
                               "language": language,
                               "apps": json.dumps(apps),
                               "apps_raw": apps,
                               "preview": preview,
                               "maps_api_key": settings.GMAPS_API_KEY })
Ejemplo n.º 18
0
def get_cases(request, domain):
    request_params = request.GET

    if request.couch_user.is_commcare_user():
        user_id = request.couch_user.get_id
    else:
        user_id = request_params.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_params.get("ids_only", "false"))
    case_id = request_params.get("case_id", "")
    footprint = string_to_boolean(request_params.get("footprint", "false"))
    accessor = CaseAccessors(domain)

    if toggles.HSPH_HACK.enabled(domain):
        hsph_case_id = request_params.get('hsph_hack', None)
        if hsph_case_id != 'None' and hsph_case_id and user_id:
            case = accessor.get_case(hsph_case_id)
            usercase_id = CommCareUser.get_by_user_id(user_id).get_usercase_id()
            usercase = accessor.get_case(usercase_id) if usercase_id else None
            return json_response(map(
                lambda case: CaseAPIResult(domain=domain, id=case['_id'], couch_doc=case, id_only=ids_only),
                filter(None, [case, case.parent, usercase])
            ))

    if case_id and not footprint:
        # 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 = accessor.get_case(case_id)
        assert case.domain == domain
        cases = [CaseAPIResult(domain=domain, id=case_id, couch_doc=case, id_only=ids_only)]
    else:
        filters = get_filters_from_request_params(request_params)
        status = api_closed_to_status(request_params.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)
    return json_response(cases)
Ejemplo n.º 19
0
def spec_value_to_boolean_or_none(user_spec_dict, key):
    value = user_spec_dict.get(key, None)
    if value and isinstance(value, str):
        return string_to_boolean(value)
    elif isinstance(value, bool):
        return value
    else:
        return None
Ejemplo n.º 20
0
 def recipients_filter(self, user):
     roles = user.user_data.get('role', [])
     if not roles:
         return False
     needs_reminders = string_to_boolean(
         user.user_data.get('needs_reminders', "False"))
     return any([role != IN_CHARGE_ROLE for role in user.user_data.get('role', [])]) and \
         needs_reminders and user.location_id
Ejemplo n.º 21
0
def are_you_sure(prompt="Are you sure you want to proceed? (yes or no): "):
    """
    Ask a user if they are sure before doing something.  Return
    whether or not they are sure
    """
    should_proceed = raw_input(prompt)
    try:
        return string_to_boolean(should_proceed)
    except Exception:
        return False
Ejemplo n.º 22
0
def are_you_sure(prompt="Are you sure you want to proceed? (yes or no): "):
    """
    Ask a user if they are sure before doing something.  Return
    whether or not they are sure
    """
    should_proceed = input(prompt)
    try:
        return string_to_boolean(should_proceed)
    except Exception:
        return False
Ejemplo n.º 23
0
 def filter_set(self):
     """
     Whether a report has any filters set. Based on whether or not there
     is a query string. This gets carried to additional asynchronous calls
     """
     are_filters_set = bool(self.request.META.get('QUERY_STRING'))
     if "filterSet" in self.request.GET:
         try:
             are_filters_set = string_to_boolean(self.request.GET.get("filterSet"))
         except ValueError:
             # not a parseable boolean
             pass
     return are_filters_set
Ejemplo n.º 24
0
def patient_from_instance(doc):
    """
    From a registration document object, create a Patient.
    """
    # TODO: clean up / un hard-code
    patient = CPatient(first_name=doc["first_name"],
                       last_name=doc["last_name"],
                       birthdate=string_to_datetime(doc["birthdate"]).date() if doc["birthdate"] else None,
                       birthdate_estimated=string_to_boolean(doc["birthdate_estimated"]),
                       gender=doc["gender"],
                       patient_id=doc["patient_id"],
                       created_on=datetime.utcnow())
    return patient
Ejemplo n.º 25
0
 def filter_set(self):
     """
     Whether a report has any filters set. Based on whether or not there
     is a query string. This gets carried to additional asynchronous calls
     """
     are_filters_set = bool(self.request.META.get('QUERY_STRING'))
     if "filterSet" in self.request.GET:
         try:
             are_filters_set = string_to_boolean(self.request.GET.get("filterSet"))
         except ValueError:
             # not a parseable boolean
             pass
     return are_filters_set
Ejemplo n.º 26
0
def load_locations(path):
    info("Loading locations %s" % (path))
    if not os.path.exists(path):
        raise Exception("no file found at %s" % path)

    count = 0
    with open(path, 'r') as f:
        reader = csv.reader(f, delimiter=',', quotechar='"')
        for row in reader:
            id, name, is_active, msd_code, parent_name, parent_type, lat, lon, group, type = row
            # for now assumes these are already create
            loc_type = LocationType.objects.get(name__iexact=type)


            parent = Location.objects.get(name__iexact=parent_name,
                                          type__name__iexact=parent_type) \
                            if parent_name and parent_type else None

            if lat and lon:
                if Point.objects.filter(longitude=lon, latitude=lat).exists():
                    point = Point.objects.filter(longitude=lon,
                                                 latitude=lat)[0]
                else:
                    point = Point.objects.create(longitude=lon, latitude=lat)
            else:
                point = None

            code = msd_code if msd_code else _get_code(type, name)
            try:
                l = Location.objects.get(code=code)
            except Location.DoesNotExist:
                l = Location(code=code)
            l.name = name
            l.type = loc_type
            l.is_active = string_to_boolean(is_active)
            if parent: l.parent = parent
            if point: l.point = point
            l.save()

            sp = supply_point_from_location\
                    (l, SupplyPointType.objects.get(name__iexact=type),
                     SupplyPoint.objects.get(location=parent) if parent else None)

            if group:
                group_obj = SupplyPointGroup.objects.get_or_create(
                    code=group)[0]
                sp.groups.add(group_obj)
                sp.save()

            count += 1
    print "Processed %d locations" % count
Ejemplo n.º 27
0
def load_locations(path):
    info("Loading locations %s"  % (path))
    if not os.path.exists(path):
        raise Exception("no file found at %s" % path)

    count = 0
    with open(path, 'r') as f:
        reader = csv.reader(f, delimiter=',', quotechar='"')
        for row in reader:
            id, name, is_active, msd_code, parent_name, parent_type, lat, lon, group, type = row
            # for now assumes these are already create
            loc_type = LocationType.objects.get(name__iexact=type)
            
            
            parent = Location.objects.get(name__iexact=parent_name, 
                                          type__name__iexact=parent_type) \
                            if parent_name and parent_type else None
            
            if lat and lon:
                if Point.objects.filter(longitude=lon, latitude=lat).exists():
                    point = Point.objects.filter(longitude=lon, latitude=lat)[0]
                else:
                    point = Point.objects.create(longitude=lon, latitude=lat)
            else:
                point = None
            
            code = msd_code if msd_code else _get_code(type, name)
            try:
                l = Location.objects.get(code=code)
            except Location.DoesNotExist:
                l = Location(code=code)
            l.name = name
            l.type = loc_type
            l.is_active = string_to_boolean(is_active)
            if parent: l.parent = parent
            if point:  l.point = point
            l.save()
            
            sp = supply_point_from_location\
                    (l, SupplyPointType.objects.get(name__iexact=type),
                     SupplyPoint.objects.get(location=parent) if parent else None)
            
            if group:
                group_obj = SupplyPointGroup.objects.get_or_create(code=group)[0]
                sp.groups.add(group_obj)
                sp.save()
            
            count += 1
    print "Processed %d locations"  % count
Ejemplo n.º 28
0
def test(request):
    dynamic = string_to_boolean(request.GET["dynamic"]) if "dynamic" in request.GET else True
    template = request.GET["template"] if "template" in request.GET \
                                       else "touchscreen/example-inner.html"
    header = request.GET["header"] if "header" in request.GET \
                                   else "Hello World!"
    pat_id = request.GET["id"] if "id" in request.GET \
                               else "000000000001" 
    try:
        patient = loader.get_patient(pat_id)
    except Exception:
        patient = None
    if dynamic:
        return render_to_response(request, "touchscreen/wrapper-dynamic.html", 
                                  {"header": header,
                                   "template": template,
                                   "patient": patient,
                                   "options": TouchscreenOptions.default()})
    else:
        return render_to_response(request, template, 
                              {"patient": patient,
                               "options": TouchscreenOptions.default()})
Ejemplo n.º 29
0
    def obj_get_list(self, bundle, **kwargs):
        domain = kwargs['domain']
        project = getattr(bundle.request, 'project', self.domain_obj(domain))
        parent_id = bundle.request.GET.get('parent_id', None)

        try:
            include_inactive = string_to_boolean(
                bundle.request.GET.get('include_inactive', False))
        except ValueError:
            include_inactive = False

        user = bundle.request.couch_user

        if not parent_id:
            if not user.has_permission(domain, 'access_all_locations'):
                raise BadRequest(LOCATION_ACCESS_DENIED)
            return SQLLocation.root_locations(domain, include_inactive)
        else:
            if not user_can_access_location_id(kwargs['domain'], user,
                                               parent_id):
                raise BadRequest(LOCATION_ACCESS_DENIED)
            parent = get_location_or_not_exist(parent_id, domain)
            return self.child_queryset(domain, include_inactive, parent)
Ejemplo n.º 30
0
def delete_user(request):
    if request.method == "POST":

        data = json.loads(request.POST.get('result'))
        if not data:
            return HttpResponseRedirect(reverse('bhoma_admin'))

        if string_to_boolean(data.get("confirm")):
            user = User.objects.get(username=data.get("username"))
            if request.user == user:
                return render_to_response(request, "touchscreen/error.html", 
                    {"error_text": "You can't delete the currently logged in user account. "
                     "Please logout and log in as a different user",
                     "options": TouchscreenOptions.admin()})
            else:
                user.delete()
        return HttpResponseRedirect(reverse("bhoma_admin"))
                                  
    return render_to_response(request, "bhoma_touchscreen.html", 
                              {'form': {'name':  'delete user', 
                                        'wfobj': 'wfDeleteUser'}, 
                               'mode':  'workflow', 
                               'dynamic_scripts': ["%swebapp/javascripts/user_del.js" % \
                                                   settings.STATIC_URL,] })
Ejemplo n.º 31
0
def spec_value_to_boolean_or_none(user_spec_dict, key):
    value = user_spec_dict.get(key) or None
    if value and isinstance(value, str):
        return string_to_boolean(value)
    return value
Ejemplo n.º 32
0
def _safe_bool(bundle, param, default=False):
    try:
        return string_to_boolean(bundle.request.GET.get(param))
    except ValueError:
        return default
Ejemplo n.º 33
0
def create_or_update_users_and_groups(domain,
                                      user_specs,
                                      group_memoizer=None,
                                      update_progress=None):
    ret = {"errors": [], "rows": []}

    group_memoizer = group_memoizer or GroupMemoizer(domain)
    group_memoizer.load_all()

    current = 0

    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)

    domain_obj = Domain.get_by_name(domain)
    allowed_group_names = [group.name for group in group_memoizer.groups]
    roles_by_name = {role.name: role for role in UserRole.by_domain(domain)}
    validators = get_user_import_validators(domain_obj, user_specs,
                                            allowed_group_names,
                                            list(roles_by_name))
    try:
        for row in user_specs:
            if update_progress:
                update_progress(current)
                current += 1

            username = row.get('username')
            status_row = {
                'username': username,
                'row': row,
            }

            try:
                for validator in validators:
                    validator(row)
            except UserUploadError as e:
                status_row['flag'] = str(e)
                ret['rows'].append(status_row)
                continue

            data = row.get('data')
            email = row.get('email')
            group_names = list(map(str, row.get('group') or []))
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            try:
                username = normalize_username(str(username),
                                              domain) if username else None
                password = str(password) if password else None

                is_active = row.get('is_active') or None
                if is_active and isinstance(is_active, str):
                    is_active = string_to_boolean(is_active)

                if user_id:
                    user = CommCareUser.get_by_user_id(user_id, domain)
                    if not user:
                        raise UserUploadError(
                            _("User with ID '{user_id}' not found").format(
                                user_id=user_id, domain=domain))

                    if username and user.username != username:
                        raise UserUploadError(
                            _('Changing usernames is not supported: %(username)r to %(new_username)r'
                              ) % {
                                  'username': user.username,
                                  'new_username': username
                              })

                    if is_password(password):
                        user.set_password(password)
                    status_row['flag'] = 'updated'
                else:
                    user = CommCareUser.create(domain,
                                               username,
                                               password,
                                               commit=False)
                    status_row['flag'] = 'created'

                if phone_number:
                    user.add_phone_number(_fmt_phone(phone_number),
                                          default=True)
                if name:
                    user.set_full_name(str(name))
                if data:
                    user.user_data.update(data)
                if uncategorized_data:
                    user.user_data.update(uncategorized_data)
                if language:
                    user.language = language
                if email:
                    user.email = email.lower()
                if is_active is not None:
                    user.is_active = is_active

                if can_assign_locations:
                    # Do this here so that we validate the location code before we
                    # save any other information to the user, this way either all of
                    # the user's information is updated, or none of it
                    location_ids = []
                    for code in location_codes:
                        loc = get_location_from_site_code(code, location_cache)
                        location_ids.append(loc.location_id)

                    locations_updated = set(
                        user.assigned_location_ids) != set(location_ids)
                    primary_location_removed = (
                        user.location_id and not location_ids
                        or user.location_id not in location_ids)

                    if primary_location_removed:
                        user.unset_location(commit=False)
                    if locations_updated:
                        user.reset_locations(location_ids, commit=False)

                if role:
                    user.set_role(domain,
                                  roles_by_name[role].get_qualified_id())

                user.save()

                if is_password(password):
                    # Without this line, digest auth doesn't work.
                    # With this line, digest auth works.
                    # Other than that, I'm not sure what's going on
                    # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                    user.get_django_user(
                        use_primary_db=True).check_password(password)

                for group in group_memoizer.by_user_id(user.user_id):
                    if group.name not in group_names:
                        group.remove_user(user)

                for group_name in group_names:
                    group_memoizer.by_name(group_name).add_user(user,
                                                                save=False)

            except (UserUploadError, CouchUser.Inconsistent) as e:
                status_row['flag'] = str(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again.")
            logging.exception(('BulkSaveError saving groups. '
                               'User saw error message "%s". Errors: %s') %
                              (_error_message, e.errors))
            ret['errors'].append(_error_message)

    return ret
Ejemplo n.º 34
0
def user_needs_reminders(user):
    return string_to_boolean(user.user_data.get('needs_reminders', 'False'))
Ejemplo n.º 35
0
def cloudcare_main(request, domain, urlPath):
    try:
        preview = string_to_boolean(request.REQUEST.get("preview", "false"))
    except ValueError:
        # this is typically only set at all if it's intended to be true so this
        # is a reasonable default for "something went wrong"
        preview = True

    app_access = ApplicationAccess.get_by_domain(domain)
    
    def _app_latest_build_json(app_id):
        build = ApplicationBase.view('app_manager/saved_app',
                                     startkey=[domain, app_id, {}],
                                     endkey=[domain, app_id],
                                     descending=True,
                                     limit=1).one()
        return get_app_json(build) if build else None

    if not preview:
        apps = get_cloudcare_apps(domain)
        # replace the apps with the last build of each app
        apps = [_app_latest_build_json(app["_id"]) for app in apps]
    else:
        apps = ApplicationBase.view('app_manager/applications_brief', startkey=[domain], endkey=[domain, {}])
        apps = [get_app_json(app) for app in apps if app and app.application_version == V2]

    # trim out empty apps
    apps = filter(lambda app: app, apps)
    apps = filter(lambda app: app_access.user_can_access_app(request.couch_user, app), apps)
    
    def _default_lang():
        if apps:
            # unfortunately we have to go back to the DB to find this
            return Application.get(apps[0]["_id"]).build_langs[0]
        else:
            return "en"

    # default language to user's preference, followed by 
    # first app's default, followed by english
    language = request.couch_user.language or _default_lang()
    
    def _url_context():
        # given a url path, returns potentially the app and case, if they're
        # selected. the front end optimizes with these to avoid excess server
        # calls

        # there's an annoying dependency between this logic and backbone's
        # url routing that seems hard to solve well. this needs to be synced
        # with apps.js if anything changes

        # for apps anything with "view/app/" works

        # for cases it will be:
        # "view/:app/:module/:form/case/:case/"
        
        # could use regex here but this is actually simpler with the potential
        # absence of a trailing slash
        split = urlPath.split('/')
        app_id = split[1] if len(split) >= 2 else None
        case_id = split[5] if len(split) >= 6 else None
        
        app = None
        if app_id:
            if app_id in [a['_id'] for a in apps]:
                app = look_up_app_json(domain, app_id)
            else:
                messages.info(request, _("That app is no longer valid. Try using the "
                                         "navigation links to select an app."))
        if app is None and len(apps) == 1:
            app = look_up_app_json(domain, apps[0]['_id'])

        def _get_case(domain, case_id):
            case = CommCareCase.get(case_id)
            assert case.domain == domain, "case %s not in %s" % (case_id, domain)
            return case.get_json()
        
        case = _get_case(domain, case_id) if case_id else None
        return {
            "app": app,
            "case": case
        }

    context = {
       "domain": domain,
       "language": language,
       "apps": apps,
       "apps_raw": apps,
       "preview": preview,
       "maps_api_key": settings.GMAPS_API_KEY
    }
    context.update(_url_context())
    return render(request, "cloudcare/cloudcare_home.html", context)
Ejemplo n.º 36
0
def cloudcare_main(request, domain, urlPath):
    preview = string_to_boolean(request.REQUEST.get("preview", "false"))
    app_access = ApplicationAccess.get_by_domain(domain)

    def _app_latest_build_json(app_id):
        build = ApplicationBase.view('app_manager/saved_app',
                                     startkey=[domain, app_id, {}],
                                     endkey=[domain, app_id],
                                     descending=True,
                                     limit=1).one()
        return build._doc if build else None

    if not preview:
        apps = get_cloudcare_apps(domain)
        # replace the apps with the last build of each app
        apps = [_app_latest_build_json(app["_id"]) for app in apps]

    else:
        apps = ApplicationBase.view('app_manager/applications_brief',
                                    startkey=[domain],
                                    endkey=[domain, {}])
        apps = [
            app._doc for app in apps
            if app and app.application_version == "2.0"
        ]

    # trim out empty apps
    apps = filter(lambda app: app, apps)
    apps = filter(
        lambda app: app_access.user_can_access_app(request.couch_user, app),
        apps)

    def _default_lang():
        if apps:
            # unfortunately we have to go back to the DB to find this
            return Application.get(apps[0]["_id"]).build_langs[0]
        else:
            return "en"

    # default language to user's preference, followed by
    # first app's default, followed by english
    language = request.couch_user.language or _default_lang()

    def _url_context():
        # given a url path, returns potentially the app and case, if they're
        # selected. the front end optimizes with these to avoid excess server
        # calls

        # there's an annoying dependency between this logic and backbone's
        # url routing that seems hard to solve well. this needs to be synced
        # with apps.js if anything changes

        # for apps anything with "view/app/" works

        # for cases it will be:
        # "view/:app/:module/:form/case/:case/"

        # could use regex here but this is actually simpler with the potential
        # absence of a trailing slash
        split = urlPath.split('/')
        app_id = split[1] if len(split) >= 2 else None
        case_id = split[5] if len(split) >= 6 else None

        app = None
        if app_id:
            if app_id in [a['_id'] for a in apps]:
                app = get_app(domain, app_id)
            else:
                messages.info(
                    request,
                    _("That app is no longer valid. Try using the "
                      "navigation links to select an app."))
        if app == None and len(apps) == 1:
            app = get_app(domain, apps[0]['_id'])

        def _get_case(domain, case_id):
            case = CommCareCase.get(case_id)
            assert case.domain == domain, "case %s not in %s" % (case_id,
                                                                 domain)
            return case.get_json()

        case = _get_case(domain, case_id) if case_id else None
        return {"app": app, "case": case}
Ejemplo n.º 37
0
def cloudcare_main(request, domain, urlPath):
    try:
        preview = string_to_boolean(request.REQUEST.get("preview", "false"))
    except ValueError:
        # this is typically only set at all if it's intended to be true so this
        # is a reasonable default for "something went wrong"
        preview = True

    app_access = ApplicationAccess.get_by_domain(domain)

    if not preview:
        apps = get_cloudcare_apps(domain)
        if request.project.use_cloudcare_releases:
            # replace the apps with the last starred build of each app, removing the ones that aren't starred
            apps = filter(lambda app: app.is_released, [get_app(domain, app['_id'], latest=True) for app in apps])
            # convert to json
            apps = [get_app_json(app) for app in apps]
        else:
            # legacy functionality - use the latest build regardless of stars
            apps = [get_app_json(ApplicationBase.get_latest_build(domain, app['_id'])) for app in apps]

    else:
        apps = ApplicationBase.view('app_manager/applications_brief', startkey=[domain], endkey=[domain, {}])
        apps = [get_app_json(app) for app in apps if app and app.application_version == V2]

    # trim out empty apps
    apps = filter(lambda app: app, apps)
    apps = filter(lambda app: app_access.user_can_access_app(request.couch_user, app), apps)
    
    def _default_lang():
        if apps:
            # unfortunately we have to go back to the DB to find this
            return Application.get(apps[0]["_id"]).build_langs[0]
        else:
            return "en"

    # default language to user's preference, followed by 
    # first app's default, followed by english
    language = request.couch_user.language or _default_lang()
    
    def _url_context():
        # given a url path, returns potentially the app, parent, and case, if
        # they're selected. the front end optimizes with these to avoid excess
        # server calls

        # there's an annoying dependency between this logic and backbone's
        # url routing that seems hard to solve well. this needs to be synced
        # with apps.js if anything changes

        # for apps anything with "view/app/" works

        # for cases it will be:
        # "view/:app/:module/:form/case/:case/"

        # if there are parent cases, it will be:
        # "view/:app/:module/:form/parent/:parent/case/:case/
        
        # could use regex here but this is actually simpler with the potential
        # absence of a trailing slash
        split = urlPath.split('/')
        app_id = split[1] if len(split) >= 2 else None

        if len(split) >= 5 and split[4] == "parent":
            parent_id = split[5]
            case_id = split[7] if len(split) >= 7 else None
        else:
            parent_id = None
            case_id = split[5] if len(split) >= 6 else None

        app = None
        if app_id:
            if app_id in [a['_id'] for a in apps]:
                app = look_up_app_json(domain, app_id)
            else:
                messages.info(request, _("That app is no longer valid. Try using the "
                                         "navigation links to select an app."))
        if app is None and len(apps) == 1:
            app = look_up_app_json(domain, apps[0]['_id'])

        def _get_case(domain, case_id):
            case = CommCareCase.get(case_id)
            assert case.domain == domain, "case %s not in %s" % (case_id, domain)
            return case.get_json()

        case = _get_case(domain, case_id) if case_id else None
        if parent_id is None and case is not None:
            parent_id = case.get('indices',{}).get('parent', {}).get('case_id', None)
        parent = _get_case(domain, parent_id) if parent_id else None

        return {
            "app": app,
            "case": case,
            "parent": parent
        }

    context = {
       "domain": domain,
       "language": language,
       "apps": apps,
       "apps_raw": apps,
       "preview": preview,
       "maps_api_key": settings.GMAPS_API_KEY,
       'offline_enabled': toggles.OFFLINE_CLOUDCARE.enabled(request.user.username),
       'sessions_enabled': request.couch_user.is_commcare_user(),
       'use_cloudcare_releases': request.project.use_cloudcare_releases,
    }
    context.update(_url_context())
    return render(request, "cloudcare/cloudcare_home.html", context)
Ejemplo n.º 38
0
    def get(self, request, domain, urlPath):
        try:
            preview = string_to_boolean(request.GET.get("preview", "false"))
        except ValueError:
            # this is typically only set at all if it's intended to be true so this
            # is a reasonable default for "something went wrong"
            preview = True

        app_access = ApplicationAccess.get_by_domain(domain)
        accessor = CaseAccessors(domain)

        if not preview:
            apps = get_cloudcare_apps(domain)
            if request.project.use_cloudcare_releases:

                if (toggles.CLOUDCARE_LATEST_BUILD.enabled(domain)
                        or toggles.CLOUDCARE_LATEST_BUILD.enabled(
                            request.couch_user.username)):
                    get_cloudcare_app = get_latest_build_doc
                else:
                    get_cloudcare_app = get_latest_released_app_doc

                apps = map(
                    lambda app: get_cloudcare_app(domain, app['_id']),
                    apps,
                )
                apps = filter(None, apps)
                apps = map(wrap_app, apps)

                # convert to json
                apps = [get_app_json(app) for app in apps]
            else:
                # legacy functionality - use the latest build regardless of stars
                apps = [
                    get_latest_build_doc(domain, app['_id']) for app in apps
                ]
                apps = [
                    get_app_json(ApplicationBase.wrap(app)) for app in apps
                    if app
                ]

        else:
            # big TODO: write a new apps view for Formplayer, can likely cut most out now
            if toggles.USE_FORMPLAYER_FRONTEND.enabled(domain):
                apps = get_cloudcare_apps(domain)
            else:
                apps = get_brief_apps_in_domain(domain)
            apps = [
                get_app_json(app) for app in apps if app and
                (isinstance(app, RemoteApp) or app.application_version == V2)
            ]
            meta = get_meta(request)
            track_clicked_preview_on_hubspot(request.couch_user,
                                             request.COOKIES, meta)

        # trim out empty apps
        apps = filter(lambda app: app, apps)
        apps = filter(
            lambda app: app_access.user_can_access_app(request.couch_user, app
                                                       ), apps)

        def _default_lang():
            if apps:
                # unfortunately we have to go back to the DB to find this
                return Application.get(apps[0]["_id"]).default_language
            else:
                return "en"

        # default language to user's preference, followed by
        # first app's default, followed by english
        language = request.couch_user.language or _default_lang()

        def _url_context():
            # given a url path, returns potentially the app, parent, and case, if
            # they're selected. the front end optimizes with these to avoid excess
            # server calls

            # there's an annoying dependency between this logic and backbone's
            # url routing that seems hard to solve well. this needs to be synced
            # with apps.js if anything changes

            # for apps anything with "view/app/" works

            # for cases it will be:
            # "view/:app/:module/:form/case/:case/"

            # if there are parent cases, it will be:
            # "view/:app/:module/:form/parent/:parent/case/:case/

            # could use regex here but this is actually simpler with the potential
            # absence of a trailing slash
            split = urlPath.split('/')
            app_id = split[1] if len(split) >= 2 else None

            if len(split) >= 5 and split[4] == "parent":
                parent_id = split[5]
                case_id = split[7] if len(split) >= 7 else None
            else:
                parent_id = None
                case_id = split[5] if len(split) >= 6 else None

            app = None
            if app_id:
                if app_id in [a['_id'] for a in apps]:
                    app = look_up_app_json(domain, app_id)
                else:
                    messages.info(
                        request,
                        _("That app is no longer valid. Try using the "
                          "navigation links to select an app."))
            if app is None and len(apps) == 1:
                app = look_up_app_json(domain, apps[0]['_id'])

            def _get_case(domain, case_id):
                case = accessor.get_case(case_id)
                assert case.domain == domain, "case %s not in %s" % (case_id,
                                                                     domain)
                return case.to_api_json()

            case = _get_case(domain, case_id) if case_id else None
            if parent_id is None and case is not None:
                parent_id = case.get('indices',
                                     {}).get('parent',
                                             {}).get('case_id', None)
Ejemplo n.º 39
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]
    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)
        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)
Ejemplo n.º 40
0
def to_boolean(val):
    return False if val == '' else string_to_boolean(val)
Ejemplo n.º 41
0
    def get(self, request, domain, urlPath):
        try:
            preview = string_to_boolean(request.GET.get("preview", "false"))
        except ValueError:
            # this is typically only set at all if it's intended to be true so this
            # is a reasonable default for "something went wrong"
            preview = True

        app_access = ApplicationAccess.get_by_domain(domain)
        accessor = CaseAccessors(domain)

        if not preview:
            apps = get_cloudcare_apps(domain)
            if request.project.use_cloudcare_releases:

                if (toggles.CLOUDCARE_LATEST_BUILD.enabled(domain) or
                        toggles.CLOUDCARE_LATEST_BUILD.enabled(request.couch_user.username)):
                    get_cloudcare_app = get_latest_build_doc
                else:
                    get_cloudcare_app = get_latest_released_app_doc

                apps = map(
                    lambda app: get_cloudcare_app(domain, app['_id']),
                    apps,
                )
                apps = filter(None, apps)
                apps = map(wrap_app, apps)

                # convert to json
                apps = [get_app_json(app) for app in apps]
            else:
                # legacy functionality - use the latest build regardless of stars
                apps = [get_latest_build_doc(domain, app['_id']) for app in apps]
                apps = [get_app_json(ApplicationBase.wrap(app)) for app in apps if app]

        else:
            # big TODO: write a new apps view for Formplayer, can likely cut most out now
            if toggles.USE_FORMPLAYER_FRONTEND.enabled(domain):
                apps = get_cloudcare_apps(domain)
            else:
                apps = get_brief_apps_in_domain(domain)
            apps = [get_app_json(app) for app in apps if app and (
                isinstance(app, RemoteApp) or app.application_version == V2)]
            meta = get_meta(request)
            track_clicked_preview_on_hubspot(request.couch_user, request.COOKIES, meta)

        # trim out empty apps
        apps = filter(lambda app: app, apps)
        apps = filter(lambda app: app_access.user_can_access_app(request.couch_user, app), apps)

        def _default_lang():
            if apps:
                # unfortunately we have to go back to the DB to find this
                return Application.get(apps[0]["_id"]).default_language
            else:
                return "en"

        # default language to user's preference, followed by
        # first app's default, followed by english
        language = request.couch_user.language or _default_lang()

        def _url_context():
            # given a url path, returns potentially the app, parent, and case, if
            # they're selected. the front end optimizes with these to avoid excess
            # server calls

            # there's an annoying dependency between this logic and backbone's
            # url routing that seems hard to solve well. this needs to be synced
            # with apps.js if anything changes

            # for apps anything with "view/app/" works

            # for cases it will be:
            # "view/:app/:module/:form/case/:case/"

            # if there are parent cases, it will be:
            # "view/:app/:module/:form/parent/:parent/case/:case/

            # could use regex here but this is actually simpler with the potential
            # absence of a trailing slash
            split = urlPath.split('/')
            app_id = split[1] if len(split) >= 2 else None

            if len(split) >= 5 and split[4] == "parent":
                parent_id = split[5]
                case_id = split[7] if len(split) >= 7 else None
            else:
                parent_id = None
                case_id = split[5] if len(split) >= 6 else None

            app = None
            if app_id:
                if app_id in [a['_id'] for a in apps]:
                    app = look_up_app_json(domain, app_id)
                else:
                    messages.info(request, _("That app is no longer valid. Try using the "
                                             "navigation links to select an app."))
            if app is None and len(apps) == 1:
                app = look_up_app_json(domain, apps[0]['_id'])

            def _get_case(domain, case_id):
                case = accessor.get_case(case_id)
                assert case.domain == domain, "case %s not in %s" % (case_id, domain)
                return case.to_api_json()

            case = _get_case(domain, case_id) if case_id else None
            if parent_id is None and case is not None:
                parent_id = case.get('indices', {}).get('parent', {}).get('case_id', None)
            parent = _get_case(domain, parent_id) if parent_id else None

            return {
                "app": app,
                "case": case,
                "parent": parent
            }

        context = {
            "domain": domain,
            "language": language,
            "apps": apps,
            "apps_raw": apps,
            "preview": preview,
            "maps_api_key": settings.GMAPS_API_KEY,
            "sessions_enabled": request.couch_user.is_commcare_user(),
            "use_cloudcare_releases": request.project.use_cloudcare_releases,
            "username": request.user.username,
            "formplayer_url": settings.FORMPLAYER_URL,
            'use_sqlite_backend': use_sqlite_backend(domain),
        }
        context.update(_url_context())
        if toggles.USE_FORMPLAYER_FRONTEND.enabled(domain):
            return render(request, "cloudcare/formplayer_home.html", context)
        else:
            return render(request, "cloudcare/cloudcare_home.html", context)
Ejemplo n.º 42
0
def _safe_bool(bundle, param, default=False):
    try:
        return string_to_boolean(bundle.request.GET.get(param))
    except ValueError:
        return default
Ejemplo n.º 43
0
def create_or_update_users_and_groups(domain, user_specs, group_specs, task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    allowed_roles = UserRole.by_domain(domain)
    roles_by_name = {role.name: role for role in allowed_roles}
    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)
    domain_obj = Domain.get_by_name(domain)
    usernames_with_dupe_passwords = users_with_duplicate_passwords(user_specs)

    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = list(map(six.text_type, row.get('group') or []))
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            if password:
                password = six.text_type(password)
            try:
                username = normalize_username(six.text_type(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username': username,
                    'row': row,
                    'flag': _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, six.string_types):
                soft_assert_type_text(is_active)
                try:
                    is_active = string_to_boolean(is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username': username,
                        'row': row,
                        'flag': _("'is_active' column can only contain 'true' or 'false'"),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    if domain_obj.strong_mobile_passwords and is_password(password):
                        if raw_username(username) in usernames_with_dupe_passwords:
                            raise UserUploadError(_("Provide a unique password for each mobile worker"))

                        try:
                            clean_password(password)
                        except forms.ValidationError:
                            if settings.ENABLE_DRACONIAN_SECURITY_FEATURES:
                                msg = _("Mobile Worker passwords must be 8 "
                                    "characters long with at least 1 capital "
                                    "letter, 1 special character and 1 number")
                            else:
                                msg = _("Please provide a stronger password")
                            raise UserUploadError(msg)

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(_(
                                'User with username %(username)r is '
                                'somehow in domain %(domain)r'
                            ) % {'username': user.username, 'domain': user.domain})
                        if username and user.username != username:
                            raise UserUploadError(_(
                                'Changing usernames is not supported: %(username)r to %(new_username)r'
                            ) % {'username': user.username, 'new_username': username})
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username': username,
                                'row': row,
                                'flag': _("username cannot contain greater than %d characters" %
                                          max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(_("Cannot create a new user with a blank password"))
                        user = CommCareUser.create(domain, username, password, commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number), default=True)
                    if name:
                        user.set_full_name(six.text_type(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        try:
                            validate_email(email)
                        except ValidationError:
                            raise UserUploadError(_("User has an invalid email address"))

                        user.email = email.lower()
                    if is_active is not None:
                        user.is_active = is_active

                    if can_assign_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        location_ids = []
                        for code in location_codes:
                            loc = get_location_from_site_code(code, location_cache)
                            location_ids.append(loc.location_id)

                    if role:
                        if role in roles_by_name:
                            user.set_role(domain, roles_by_name[role].get_qualified_id())
                        else:
                            raise UserUploadError(_(
                                "Role '%s' does not exist"
                            ) % role)

                    if can_assign_locations:
                        locations_updated = set(user.assigned_location_ids) != set(location_ids)
                        primary_location_removed = (user.location_id and not location_ids or
                                                    user.location_id not in location_ids)

                        if primary_location_removed:
                            user.unset_location(commit=False)
                        if locations_updated:
                            user.reset_locations(location_ids, commit=False)

                    user.save()

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                        user.get_django_user(use_primary_db=True).check_password(password)

                    for group_id in Group.by_user(user, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(_(
                                "Can't add to group '%s' "
                                "(try adding it to your spreadsheet)"
                            ) % group_name)
                        group_memoizer.by_name(group_name).add_user(user, save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = six.text_type(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again."
            )
            logging.exception((
                'BulkSaveError saving groups. '
                'User saw error message "%s". Errors: %s'
            ) % (_error_message, e.errors))
            ret['errors'].append(_error_message)

    _set_progress(total)
    return ret
Ejemplo n.º 44
0
def create_or_update_users_and_groups(domain, user_specs, group_specs, location_specs, task=None):
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs) + len(location_specs)
    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    can_access_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_access_locations:
        location_cache = SiteCodeToLocationCache(domain)
    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = map(unicode, row.get('group') or [])
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_code = row.get('location-sms-code', '')

            if password:
                password = unicode(password)
            try:
                username = normalize_username(str(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username': username,
                    'row': row,
                    'flag': _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, basestring):
                try:
                    is_active = string_to_boolean(is_active)
                except ValueError:
                    ret['rows'].append({
                        'username': username,
                        'row': row,
                        'flag': _("'is_active' column can only contain 'true' or 'false'"),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    def is_password(password):
                        if not password:
                            return False
                        for c in password:
                            if c != "*":
                                return True
                        return False

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(_(
                                'User with username %(username)r is '
                                'somehow in domain %(domain)r'
                            ) % {'username': user.username, 'domain': user.domain})
                        if username and user.username != username:
                            user.change_username(username)
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        if len(raw_username(username)) > CommCareAccountForm.max_len_username:
                            ret['rows'].append({
                                'username': username,
                                'row': row,
                                'flag': _("username cannot contain greater than %d characters" %
                                          CommCareAccountForm.max_len_username)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(_("Cannot create a new user with a blank password"))
                        user = CommCareUser.create(domain, username, password, commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number), default=True)
                    if name:
                        user.set_full_name(name)
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        user.email = email
                    if is_active is not None:
                        user.is_active = is_active

                    user.save()
                    if can_access_locations and location_code:
                        loc = location_cache.get(location_code)
                        if user.location_id != loc._id:
                            # this triggers a second user save so
                            # we want to avoid doing it if it isn't
                            # needed
                            user.set_location(loc)
                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        user.get_django_user().check_password(password)

                    for group_id in Group.by_user(user, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user, save=False)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(_(
                                "Can't add to group '%s' "
                                "(try adding it to your spreadsheet)"
                            ) % group_name)
                        group_memoizer.by_name(group_name).add_user(user, save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = unicode(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again."
            )
            logging.exception((
                'BulkSaveError saving groups. '
                'User saw error message "%s". Errors: %s'
            ) % (_error_message, e.errors))
            ret['errors'].append(_error_message)

    if Domain.get_by_name(domain).supports_multiple_locations_per_user:
        create_or_update_locations(domain, location_specs, log=ret)
    _set_progress(total)
    return ret
Ejemplo n.º 45
0
def create_or_update_users_and_groups(domain, user_specs, group_specs, location_specs, task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs) + len(location_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    can_access_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_access_locations:
        location_cache = SiteCodeToLocationCache(domain)
    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = map(unicode, row.get('group') or [])
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_code = row.get('location_code', '')

            if password:
                password = unicode(password)
            try:
                username = normalize_username(str(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username': username,
                    'row': row,
                    'flag': _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, basestring):
                try:
                    is_active = string_to_boolean(is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username': username,
                        'row': row,
                        'flag': _("'is_active' column can only contain 'true' or 'false'"),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    def is_password(password):
                        if not password:
                            return False
                        for c in password:
                            if c != "*":
                                return True
                        return False

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(_(
                                'User with username %(username)r is '
                                'somehow in domain %(domain)r'
                            ) % {'username': user.username, 'domain': user.domain})
                        if username and user.username != username:
                            user.change_username(username)
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username': username,
                                'row': row,
                                'flag': _("username cannot contain greater than %d characters" %
                                          max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(_("Cannot create a new user with a blank password"))
                        user = CommCareUser.create(domain, username, password, commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number), default=True)
                    if name:
                        user.set_full_name(unicode(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        email_validator = EmailValidator()
                        try:
                            email_validator(email)
                            user.email = email
                        except ValidationError:
                            raise UserUploadError(_("User has an invalid email address"))
                    if is_active is not None:
                        user.is_active = is_active

                    if can_access_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        if location_code:
                            loc = get_location_from_site_code(location_code, location_cache)
                        else:
                            loc = None

                    user.save()
                    if can_access_locations and loc:
                        if user.location_id != loc.location_id:
                            # this triggers a second user save so
                            # we want to avoid doing it if it isn't
                            # needed
                            user.set_location(loc)

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        user.get_django_user().check_password(password)

                    for group_id in Group.by_user(user, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user, save=False)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(_(
                                "Can't add to group '%s' "
                                "(try adding it to your spreadsheet)"
                            ) % group_name)
                        group_memoizer.by_name(group_name).add_user(user, save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = unicode(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again."
            )
            logging.exception((
                'BulkSaveError saving groups. '
                'User saw error message "%s". Errors: %s'
            ) % (_error_message, e.errors))
            ret['errors'].append(_error_message)

    if Domain.get_by_name(domain).supports_multiple_locations_per_user:
        create_or_update_locations(domain, location_specs, log=ret)
    _set_progress(total)
    return ret
Ejemplo n.º 46
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)
Ejemplo n.º 47
0
def user_needs_reminders(user):
    return string_to_boolean(user.user_data.get('needs_reminders', 'False'))
Ejemplo n.º 48
0
        return HttpResponseBadRequest("Must specify user_id!")

    ids_only = string_to_boolean(request.REQUEST.get("ids_only", "false"))
    case_id = request.REQUEST.get("case_id", "")
    if case_id:
        # 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:
        footprint = string_to_boolean(request.REQUEST.get(
            "footprint", "false"))
        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)
    return json_response(cases)


@cloudcare_api
Ejemplo n.º 49
0
def create_or_update_users_and_groups(domain,
                                      user_specs,
                                      group_specs,
                                      task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    allowed_roles = UserRole.by_domain(domain)
    roles_by_name = {role.name: role for role in allowed_roles}
    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)
    domain_obj = Domain.get_by_name(domain)
    usernames_with_dupe_passwords = users_with_duplicate_passwords(user_specs)

    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = list(map(str, row.get('group') or []))
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            if password:
                password = str(password)
            try:
                username = normalize_username(str(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username':
                    username,
                    'row':
                    row,
                    'flag':
                    _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, str):
                try:
                    is_active = string_to_boolean(
                        is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username':
                        username,
                        'row':
                        row,
                        'flag':
                        _("'is_active' column can only contain 'true' or 'false'"
                          ),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    if domain_obj.strong_mobile_passwords and is_password(
                            password):
                        if raw_username(
                                username) in usernames_with_dupe_passwords:
                            raise UserUploadError(
                                _("Provide a unique password for each mobile worker"
                                  ))

                        try:
                            clean_password(password)
                        except forms.ValidationError:
                            if settings.ENABLE_DRACONIAN_SECURITY_FEATURES:
                                msg = _(
                                    "Mobile Worker passwords must be 8 "
                                    "characters long with at least 1 capital "
                                    "letter, 1 special character and 1 number")
                            else:
                                msg = _("Please provide a stronger password")
                            raise UserUploadError(msg)

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(
                                _('User with username %(username)r is '
                                  'somehow in domain %(domain)r') % {
                                      'username': user.username,
                                      'domain': user.domain
                                  })
                        if username and user.username != username:
                            raise UserUploadError(
                                _('Changing usernames is not supported: %(username)r to %(new_username)r'
                                  ) % {
                                      'username': user.username,
                                      'new_username': username
                                  })
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(
                            domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username':
                                username,
                                'row':
                                row,
                                'flag':
                                _("username cannot contain greater than %d characters"
                                  % max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(
                                _("Cannot create a new user with a blank password"
                                  ))
                        user = CommCareUser.create(domain,
                                                   username,
                                                   password,
                                                   commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number),
                                              default=True)
                    if name:
                        user.set_full_name(str(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        try:
                            validate_email(email)
                        except ValidationError:
                            raise UserUploadError(
                                _("User has an invalid email address"))

                        user.email = email.lower()
                    if is_active is not None:
                        user.is_active = is_active

                    if can_assign_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        location_ids = []
                        for code in location_codes:
                            loc = get_location_from_site_code(
                                code, location_cache)
                            location_ids.append(loc.location_id)

                    if role:
                        if role in roles_by_name:
                            user.set_role(
                                domain, roles_by_name[role].get_qualified_id())
                        else:
                            raise UserUploadError(
                                _("Role '%s' does not exist") % role)

                    if can_assign_locations:
                        locations_updated = set(
                            user.assigned_location_ids) != set(location_ids)
                        primary_location_removed = (
                            user.location_id and not location_ids
                            or user.location_id not in location_ids)

                        if primary_location_removed:
                            user.unset_location(commit=False)
                        if locations_updated:
                            user.reset_locations(location_ids, commit=False)

                    user.save()

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                        user.get_django_user(
                            use_primary_db=True).check_password(password)

                    for group_id in Group.by_user_id(user.user_id, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(
                                _("Can't add to group '%s' "
                                  "(try adding it to your spreadsheet)") %
                                group_name)
                        group_memoizer.by_name(group_name).add_user(user,
                                                                    save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = str(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again.")
            logging.exception(('BulkSaveError saving groups. '
                               'User saw error message "%s". Errors: %s') %
                              (_error_message, e.errors))
            ret['errors'].append(_error_message)

    _set_progress(total)
    return ret
Ejemplo n.º 50
0
def to_boolean(val):
    return False if val == '' else string_to_boolean(val)
Ejemplo n.º 51
0
def cloudcare_main(request, domain, urlPath):
    try:
        preview = string_to_boolean(request.REQUEST.get("preview", "false"))
    except ValueError:
        # this is typically only set at all if it's intended to be true so this
        # is a reasonable default for "something went wrong"
        preview = True

    app_access = ApplicationAccess.get_by_domain(domain)

    if not preview:
        apps = get_cloudcare_apps(domain)
        if request.project.use_cloudcare_releases:
            # replace the apps with the last starred build of each app, removing the ones that aren't starred
            apps = filter(
                lambda app: app.is_released,
                [get_app(domain, app['_id'], latest=True) for app in apps])
            # convert to json
            apps = [get_app_json(app) for app in apps]
        else:
            # legacy functionality - use the latest build regardless of stars
            apps = [
                get_app_json(
                    ApplicationBase.get_latest_build(domain, app['_id']))
                for app in apps
            ]

    else:
        apps = ApplicationBase.view('app_manager/applications_brief',
                                    startkey=[domain],
                                    endkey=[domain, {}])
        apps = [
            get_app_json(app) for app in apps
            if app and app.application_version == V2
        ]

    # trim out empty apps
    apps = filter(lambda app: app, apps)
    apps = filter(
        lambda app: app_access.user_can_access_app(request.couch_user, app),
        apps)

    def _default_lang():
        if apps:
            # unfortunately we have to go back to the DB to find this
            return Application.get(apps[0]["_id"]).build_langs[0]
        else:
            return "en"

    # default language to user's preference, followed by
    # first app's default, followed by english
    language = request.couch_user.language or _default_lang()

    def _url_context():
        # given a url path, returns potentially the app, parent, and case, if
        # they're selected. the front end optimizes with these to avoid excess
        # server calls

        # there's an annoying dependency between this logic and backbone's
        # url routing that seems hard to solve well. this needs to be synced
        # with apps.js if anything changes

        # for apps anything with "view/app/" works

        # for cases it will be:
        # "view/:app/:module/:form/case/:case/"

        # if there are parent cases, it will be:
        # "view/:app/:module/:form/parent/:parent/case/:case/

        # could use regex here but this is actually simpler with the potential
        # absence of a trailing slash
        split = urlPath.split('/')
        app_id = split[1] if len(split) >= 2 else None

        if len(split) >= 5 and split[4] == "parent":
            parent_id = split[5]
            case_id = split[7] if len(split) >= 7 else None
        else:
            parent_id = None
            case_id = split[5] if len(split) >= 6 else None

        app = None
        if app_id:
            if app_id in [a['_id'] for a in apps]:
                app = look_up_app_json(domain, app_id)
            else:
                messages.info(
                    request,
                    _("That app is no longer valid. Try using the "
                      "navigation links to select an app."))
        if app is None and len(apps) == 1:
            app = look_up_app_json(domain, apps[0]['_id'])

        def _get_case(domain, case_id):
            case = CommCareCase.get(case_id)
            assert case.domain == domain, "case %s not in %s" % (case_id,
                                                                 domain)
            return case.get_json()

        case = _get_case(domain, case_id) if case_id else None
        if parent_id is None and case is not None:
            parent_id = case.get('indices', {}).get('parent',
                                                    {}).get('case_id', None)