def test_update_web_apps_list(self): self.assertEqual([], UserRole.by_domain(self.linked_domain)) report_mapping = {'master_report_id': 'linked_report_id'} with patch('corehq.apps.linked_domain.updates.get_static_report_mapping', return_value=report_mapping): update_user_roles(self.domain_link) roles = UserRole.by_domain(self.linked_domain) self.assertEqual(1, len(roles)) self.assertEqual(roles[0].permissions.view_web_apps_list, [self.linked_app._id]) self.assertEqual(roles[0].permissions.view_report_list, [get_ucr_class_name('linked_report_id')])
def _has_helpdesk_role(domain, couch_user): user_roles = UserRole.by_domain(domain) helpdesk_roles_id = [ role.get_id for role in user_roles if role.name in const.HELPDESK_ROLES ] domain_membership = couch_user.get_domain_membership(domain) return domain_membership.role_id in helpdesk_roles_id
def get_editable_role_choices(domain, couch_user, allow_admin_role, use_qualified_id=True): """ :param domain: roles for domain :param couch_user: user accessing the roles :param allow_admin_role: to include admin role, in case user is admin :param use_qualified_id: use role's qualified id as the id for the choice else the db id """ def role_to_choice(role): return (role.get_qualified_id() if use_qualified_id else role.get_id, role.name or _('(No Name)')) roles = UserRole.by_domain(domain) if not couch_user.is_domain_admin(domain): try: user_role = couch_user.get_role(domain) except DomainMembershipError: user_role = None user_role_id = user_role.get_id if user_role else None roles = [ role for role in roles if role.accessible_by_non_admin_role(user_role_id) ] elif allow_admin_role: roles = [AdminUserRole(domain=domain)] + roles return [role_to_choice(role) for role in roles]
def __init__(self, *args, **kwargs): self.domain = kwargs.pop('domain') super(CommCareUserFilterForm, self).__init__(*args, **kwargs) roles = UserRole.by_domain(self.domain) self.fields['role_id'].choices = [('', _('All Roles'))] + [ (role._id, role.name or _('(No Name)')) for role in roles] self.helper = FormHelper() self.helper.form_method = 'GET' self.helper.form_id = 'user-filters' self.helper.form_class = 'form-horizontal' self.helper.form_action = reverse('download_commcare_users', args=[self.domain]) self.helper.label_class = 'col-sm-3 col-md-2' self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6' self.helper.form_text_inline = True self.helper.layout = crispy.Layout( crispy.Fieldset( _("Filter and Download Users"), crispy.Field('role_id'), crispy.Field('search_string'), ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Download All Users"), type="submit", css_class="btn btn-success submit_button", ) ), )
def orgs_team_members(request, org, team_id, template="orgs/orgs_team_members.html"): organization = Organization.get_by_name(org) ctxt = base_context(request, organization) ctxt["tab"] = "teams" try: team = Team.get(team_id) except ResourceNotFound: raise Http404("Team %s does not exist" % team_id) team_members = team.get_members() team_members.sort(key=lambda user: user.username) # inspect the domains of the team domain_names = team.get_domains() team_domains = list() for name in domain_names: team_domains.append([Domain.get_by_name(name), team.role_label(domain=name), UserRole.by_domain(name)]) nonmembers = [ m.username for m in filter(lambda m: m.username not in [tm.username for tm in team_members], ctxt["members"]) ] nondomains = [d.name for d in filter(lambda d: d.name not in [td[0].name for td in team_domains], ctxt["domains"])] ctxt.update( dict( team=team, team_members=team_members, nonmembers=nonmembers, team_domains=team_domains, nondomains=nondomains, ) ) return render(request, template, ctxt)
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend( sorted(UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else '\uFFFF')) show_es_issue = False # skip the admin role since it's not editable for role in user_roles[1:]: try: role.hasUsersAssigned = bool(role.ids_of_assigned_users) except TypeError: # when query_result['hits'] returns None due to an ES issue show_es_issue = True role.has_unpermitted_location_restriction = ( not self.can_restrict_access_by_location and not role.permissions.access_all_locations) if show_es_issue: messages.error( self.request, mark_safe( _("We might be experiencing issues fetching the entire list " "of user roles right now. This issue is likely temporary and " "nothing to worry about, but if you keep seeing this for " "more than a day, please <a href='#modalReportIssue' " "data-toggle='modal'>Report an Issue</a>."))) return user_roles
def __init__(self, *args, **kwargs): self.domain = kwargs.pop('domain') super(CommCareUserFilterForm, self).__init__(*args, **kwargs) roles = UserRole.by_domain(self.domain) self.fields['role_id'].choices = [('', _('All Roles'))] + [ (role._id, role.name or _('(No Name)')) for role in roles] self.helper = FormHelper() self.helper.form_method = 'GET' self.helper.form_id = 'user-filters' self.helper.form_class = 'form-horizontal' self.helper.form_action = reverse('download_commcare_users', args=[self.domain]) self.helper.label_class = 'col-sm-3 col-md-2' self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6' self.helper.form_text_inline = True self.helper.layout = crispy.Layout( crispy.Fieldset( _("Filter and Download Users"), crispy.Field('role_id'), crispy.Field('search_string'), ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Download All Users"), type="submit", css_class="btn btn-primary submit_button", ) ), )
def _get_domain_info(domain): domain_info = domain_info_by_domain.get(domain) if domain_info: return domain_info if domain == upload_domain: domain_group_memoizer = group_memoizer or GroupMemoizer(domain) else: domain_group_memoizer = GroupMemoizer(domain) domain_group_memoizer.load_all() can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS) location_cache = None if can_assign_locations: location_cache = SiteCodeToLocationCache(domain) domain_obj = Domain.get_by_name(domain) allowed_group_names = [group.name for group in domain_group_memoizer.groups] roles_by_name = {role.name: role for role in UserRole.by_domain(domain)} domain_user_specs = [spec for spec in user_specs if spec.get('domain', upload_domain) == domain] validators = get_user_import_validators( domain_obj, domain_user_specs, allowed_group_names, list(roles_by_name), upload_domain ) domain_info = DomainInfo( validators, can_assign_locations, location_cache, roles_by_name, domain_group_memoizer ) domain_info_by_domain[domain] = domain_info return domain_info
def orgs_team_members(request, org, team_id, template="orgs/orgs_team_members.html"): class TeamMembersNotification(Notification): doc_type = 'OrgTeamMembersNotification' def template(self): return 'orgs/partials/team_members_notification.html' MainNotification.display_if_needed(messages, request, ctxt={"org": request.organization}) TeamMembersNotification.display_if_needed(messages, request) ctxt = base_context(request, request.organization) ctxt["tab"] = "teams" try: team = Team.get(team_id) except ResourceNotFound: raise Http404("Team %s does not exist" % team_id) team_members = team.get_members() team_members.sort(key=lambda user: user.username) #inspect the domains of the team domain_names = team.get_domains() team_domains = list() for name in domain_names: team_domains.append([Domain.get_by_name(name), team.role_label(domain=name), UserRole.by_domain(name)]) nonmembers = filter(lambda m: m.username not in [tm.username for tm in team_members], ctxt["members"]) nondomains = filter(lambda d: d.name not in [td[0].name for td in team_domains], ctxt["domains"]) ctxt.update(dict(team=team, team_members=team_members, nonmembers=nonmembers, team_domains=team_domains, nondomains=nondomains)) return render(request, template, ctxt)
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend(sorted( UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else '\uFFFF' )) show_es_issue = False # skip the admin role since it's not editable for role in user_roles[1:]: try: role.hasUsersAssigned = bool(role.ids_of_assigned_users) except TypeError: # when query_result['hits'] returns None due to an ES issue show_es_issue = True role.has_unpermitted_location_restriction = ( not self.can_restrict_access_by_location and not role.permissions.access_all_locations ) if show_es_issue: messages.error( self.request, mark_safe(_( "We might be experiencing issues fetching the entire list " "of user roles right now. This issue is likely temporary and " "nothing to worry about, but if you keep seeing this for " "more than a day, please <a href='#modalReportIssue' " "data-toggle='modal'>Report an Issue</a>." )) ) return user_roles
def setUp(self): super(TestUserRoleSubscriptionChanges, self).setUp() self.domain = generator.arbitrary_domain() UserRole.init_domain_with_presets(self.domain.name) self.user_roles = UserRole.by_domain(self.domain.name) self.custom_role = UserRole.get_or_create_with_permissions( self.domain.name, Permissions(edit_apps=True, edit_web_users=True), "Custom Role" ) self.custom_role.save() self.read_only_role = UserRole.get_read_only_role_by_domain(self.domain.name) self.admin_user = generator.arbitrary_web_user() self.admin_user.add_domain_membership(self.domain.name, is_admin=True) self.admin_user.save() self.web_users = [] self.commcare_users = [] for role in [self.custom_role] + self.user_roles: web_user = generator.arbitrary_web_user() web_user.add_domain_membership(self.domain.name, role_id=role.get_id) web_user.save() self.web_users.append(web_user) commcare_user = generator.arbitrary_commcare_user( domain=self.domain.name) commcare_user.set_role(self.domain.name, role.get_qualified_id()) commcare_user.save() self.commcare_users.append(commcare_user) self.account = BillingAccount.get_or_create_account_by_domain( self.domain.name,created_by=self.admin_user.username)[0] self.advanced_plan = DefaultProductPlan.get_default_plan_by_domain( self.domain.name,edition=SoftwarePlanEdition.ADVANCED)
def setUpClass(cls): super(AllCommCareUsersTest, cls).setUpClass() delete_all_users() hard_delete_deleted_users() cls.ccdomain = Domain(name='cc_user_domain') cls.ccdomain.save() cls.other_domain = Domain(name='other_domain') cls.other_domain.save() UserRole.init_domain_with_presets(cls.ccdomain.name) cls.user_roles = UserRole.by_domain(cls.ccdomain.name) cls.custom_role = UserRole.get_or_create_with_permissions( cls.ccdomain.name, Permissions( edit_apps=True, edit_web_users=True, view_web_users=True, view_roles=True, ), "Custom Role" ) cls.custom_role.save() cls.ccuser_1 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_2 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_2.set_role(cls.ccdomain.name, cls.custom_role.get_qualified_id()) cls.ccuser_2.save() cls.web_user = WebUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_other_domain = CommCareUser.create( domain=cls.other_domain.name, username='******', password='******', email='*****@*****.**', ) cls.retired_user = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.retired_user.retire()
def test_update_report_list(self): self.assertEqual([], UserRole.by_domain(self.linked_domain)) report_mapping = {'master_report_id': 'linked_report_id'} with patch( 'corehq.apps.linked_domain.updates.get_static_report_mapping', return_value=report_mapping): update_user_roles(self.domain_link) roles = {r.name: r for r in UserRole.by_domain(self.linked_domain)} self.assertEqual(2, len(roles)) self.assertEqual(roles['test'].permissions.view_report_list, [get_ucr_class_name('linked_report_id')]) self.assertTrue(roles['test'].is_non_admin_editable) self.assertTrue(roles['other_test'].permissions.edit_web_users) self.assertEqual(roles['other_test'].assignable_by, [roles['test'].get_id])
def setUpClass(cls): super(AllCommCareUsersTest, cls).setUpClass() delete_all_users() hard_delete_deleted_users() cls.ccdomain = Domain(name='cc_user_domain') cls.ccdomain.save() cls.other_domain = Domain(name='other_domain') cls.other_domain.save() UserRole.init_domain_with_presets(cls.ccdomain.name) cls.user_roles = UserRole.by_domain(cls.ccdomain.name) cls.custom_role = UserRole.get_or_create_with_permissions( cls.ccdomain.name, Permissions( edit_apps=True, edit_web_users=True, view_web_users=True, view_roles=True, ), "Custom Role") cls.custom_role.save() cls.ccuser_1 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_2 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_2.set_role(cls.ccdomain.name, cls.custom_role.get_qualified_id()) cls.ccuser_2.save() cls.web_user = WebUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.ccuser_other_domain = CommCareUser.create( domain=cls.other_domain.name, username='******', password='******', email='*****@*****.**', ) cls.retired_user = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', email='*****@*****.**', ) cls.retired_user.retire()
def web_users(request, domain, template="users/web_users.html"): context = _users_context(request, domain) user_roles = [AdminUserRole(domain=domain)] user_roles.extend(sorted(UserRole.by_domain(domain), key=lambda role: role.name if role.name else u'\uFFFF')) context.update({ 'user_roles': user_roles, 'default_role': UserRole.get_default(), 'report_list': get_possible_reports(domain), }) return render_to_response(request, template, context)
def _get_editable_role_choices(domain, couch_user, allow_admin_role): def role_to_choice(role): return (role.get_qualified_id(), role.name or _('(No Name)')) roles = UserRole.by_domain(domain) if not couch_user.is_domain_admin(domain): roles = [role for role in roles if role.is_non_admin_editable] elif allow_admin_role: roles = [AdminUserRole(domain=domain)] + roles return [role_to_choice(role) for role in roles]
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend(sorted(UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else u'\uFFFF')) # indicate if a role has assigned users, skip admin role for i in range(1, len(user_roles)): role = user_roles[i] role.__setattr__('hasUsersAssigned', True if len(role.ids_of_assigned_users) > 0 else False) return user_roles
def test_match_ids(self): self.assertEqual([], UserRole.by_domain(self.linked_domain)) role = UserRole(domain=self.linked_domain, name='id_test', permissions=Permissions( edit_web_users=False, view_locations=True, ), assignable_by=[self.role.get_id], upstream_id=self.other_role.get_id) role.save() update_user_roles(self.domain_link) roles = {r.name: r for r in UserRole.by_domain(self.linked_domain)} self.assertEqual(2, len(roles)) self.assertIsNotNone(roles.get('other_test')) self.assertTrue(roles['other_test'].permissions.edit_web_users) self.assertEqual(roles['other_test'].upstream_id, self.other_role.get_id)
def response_role_based_access(self): """ Perform Role Based Access Upgrade - Un-archive custom roles. """ if self.verbose: num_archived_roles = len( UserRole.by_domain(self.domain.name, is_archived=True)) if num_archived_roles: print "Re-Activating %d archived roles." % num_archived_roles UserRole.unarchive_roles_for_domain(self.domain.name) return True
def response_role_based_access(self): """ Perform Role Based Access Upgrade - Un-archive custom roles. """ if self.verbose: num_archived_roles = len(UserRole.by_domain(self.domain.name, is_archived=True)) if num_archived_roles: print "Re-Activating %d archived roles." % num_archived_roles UserRole.unarchive_roles_for_domain(self.domain.name) return True
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend( sorted(UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else u'\uFFFF')) # skip the admin role since it's not editable for role in user_roles[1:]: role.hasUsersAssigned = bool(role.ids_of_assigned_users) role.has_unpermitted_location_restriction = ( not self.can_restrict_access_by_location and not role.permissions.access_all_locations) return user_roles
def __init__(self, *args, **kwargs): from corehq.apps.locations.forms import LocationSelectWidget from corehq.apps.users.views import get_editable_role_choices self.domain = kwargs.pop('domain') self.couch_user = kwargs.pop('couch_user') super(CommCareUserFilterForm, self).__init__(*args, **kwargs) self.fields['location_id'].widget = LocationSelectWidget(self.domain) self.fields['location_id'].help_text = ExpandedMobileWorkerFilter.location_search_help if is_icds_cas_project(self.domain) and not self.couch_user.is_domain_admin(self.domain): roles = get_editable_role_choices(self.domain, self.couch_user, allow_admin_role=True, use_qualified_id=False) self.fields['role_id'].choices = roles else: roles = UserRole.by_domain(self.domain) self.fields['role_id'].choices = [('', _('All Roles'))] + [ (role._id, role.name or _('(No Name)')) for role in roles] self.fields['domains'].choices = [(self.domain, self.domain)] if len(DomainPermissionsMirror.mirror_domains(self.domain)) > 0: self.fields['domains'].choices = [('all_project_spaces', _('All Project Spaces'))] + \ [(self.domain, self.domain)] + \ [(domain, domain) for domain in DomainPermissionsMirror.mirror_domains(self.domain)] self.helper = FormHelper() self.helper.form_method = 'GET' self.helper.form_id = 'user-filters' self.helper.form_class = 'form-horizontal' self.helper.form_action = reverse('download_commcare_users', args=[self.domain]) self.helper.label_class = 'col-sm-3 col-md-2' self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6' self.helper.form_text_inline = True self.helper.layout = crispy.Layout( crispy.Fieldset( _("Filter and Download Users"), crispy.Field('role_id', css_class="hqwebapp-select2"), crispy.Field('search_string'), crispy.Field('location_id'), crispy.Field('columns'), crispy.Field('domains'), ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Download All Users"), type="submit", css_class="btn btn-primary submit_button", ) ), )
def setUp(self): super(TestUserRoleSubscriptionChanges, self).setUp() self.domain = Domain( name="test-sub-changes", is_active=True, ) self.domain.save() self.other_domain = Domain( name="other-domain", is_active=True, ) self.other_domain.save() UserRole.init_domain_with_presets(self.domain.name) self.user_roles = UserRole.by_domain(self.domain.name) self.custom_role = UserRole.get_or_create_with_permissions( self.domain.name, Permissions( edit_apps=True, edit_web_users=True, view_web_users=True, view_roles=True, ), "Custom Role") self.custom_role.save() self.read_only_role = UserRole.get_read_only_role_by_domain( self.domain.name) self.admin_username = generator.create_arbitrary_web_user_name() self.web_users = [] self.commcare_users = [] for role in [self.custom_role] + self.user_roles: web_user = WebUser.create( self.other_domain.name, generator.create_arbitrary_web_user_name(), 'test123', None, None) web_user.is_active = True web_user.add_domain_membership(self.domain.name, role_id=role.get_id) web_user.save() self.web_users.append(web_user) commcare_user = generator.arbitrary_commcare_user( domain=self.domain.name) commcare_user.set_role(self.domain.name, role.get_qualified_id()) commcare_user.save() self.commcare_users.append(commcare_user) self.account = BillingAccount.get_or_create_account_by_domain( self.domain.name, created_by=self.admin_username)[0] self.advanced_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED)
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend(sorted( UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else u'\uFFFF' )) # skip the admin role since it's not editable for role in user_roles[1:]: role.hasUsersAssigned = bool(role.ids_of_assigned_users) role.has_unpermitted_location_restriction = ( not self.can_restrict_access_by_location and not role.permissions.access_all_locations ) return user_roles
def update_user_roles(domain_link): if domain_link.is_remote: master_results = remote_get_user_roles(domain_link) else: master_results = local_get_user_roles(domain_link.master_domain) _convert_reports_permissions(domain_link, master_results) local_roles = UserRole.by_domain(domain_link.linked_domain, include_archived=True) local_roles_by_name = {} local_roles_by_upstream_id = {} for role in local_roles: local_roles_by_name[role.name] = role if role.upstream_id: local_roles_by_upstream_id[role.upstream_id] = role # Update downstream roles based on upstream roles for role_def in master_results: role = local_roles_by_upstream_id.get( role_def['_id']) or local_roles_by_name.get(role_def['name']) if role: role_json = role.to_json() else: role_json = {'domain': domain_link.linked_domain} role_json['upstream_id'] = role_def['_id'] upstream_role = copy(role_def) upstream_role.pop('_id') upstream_role.pop('upstream_id') role_json.update(upstream_role) local_roles_by_upstream_id[role_json['upstream_id']] = role_json UserRole.wrap(role_json).save() # Update assignable_by ids - must be done after main update to guarantee all local roles have ids for role in local_roles_by_upstream_id.values(): if role['assignable_by']: role['assignable_by'] = [ local_roles_by_upstream_id[role_id]['_id'] for role_id in role['assignable_by'] ] UserRole.wrap(role).save()
def web_users(request, domain, template="users/web_users.html"): context = _users_context(request, domain) user_roles = [AdminUserRole(domain=domain)] user_roles.extend(sorted(UserRole.by_domain(domain), key=lambda role: role.name if role.name else u'\uFFFF')) role_labels = {} for r in user_roles: key = 'user-role:%s' % r.get_id if r.get_id else r.get_qualified_id() role_labels[key] = r.name invitations = DomainInvitation.by_domain(domain) for invitation in invitations: invitation.role_label = role_labels.get(invitation.role, "") context.update({ 'user_roles': user_roles, 'default_role': UserRole.get_default(), 'report_list': get_possible_reports(domain), 'invitations': invitations }) return render(request, template, context)
def orgs_team_members(request, org, team_id, template="orgs/orgs_team_members.html"): ctxt = base_context(request, request.organization) ctxt["tab"] = "teams" try: team = Team.get(team_id) except ResourceNotFound: raise Http404("Team %s does not exist" % team_id) team_members = team.get_members() team_members.sort(key=lambda user: user.username) #inspect the domains of the team domain_names = team.get_domains() team_domains = list() for name in domain_names: team_domains.append([ Domain.get_by_name(name), team.role_label(domain=name), UserRole.by_domain(name) ]) nonmembers = filter( lambda m: m.username not in [tm.username for tm in team_members], ctxt["members"]) nondomains = filter( lambda d: d.name not in [td[0].name for td in team_domains], ctxt["domains"]) ctxt.update( dict(team=team, team_members=team_members, nonmembers=nonmembers, team_domains=team_domains, nondomains=nondomains)) return render(request, template, ctxt)
def __init__(self, *args, **kwargs): from corehq.apps.locations.forms import LocationSelectWidget self.domain = kwargs.pop('domain') super(CommCareUserFilterForm, self).__init__(*args, **kwargs) self.fields['location_id'].widget = LocationSelectWidget(self.domain) self.fields[ 'location_id'].help_text = ExpandedMobileWorkerFilter.location_search_help roles = UserRole.by_domain(self.domain) self.fields['role_id'].choices = [('', _('All Roles'))] + [ (role._id, role.name or _('(No Name)')) for role in roles ] self.helper = FormHelper() self.helper.form_method = 'GET' self.helper.form_id = 'user-filters' self.helper.form_class = 'form-horizontal' self.helper.form_action = reverse('download_commcare_users', args=[self.domain]) self.helper.label_class = 'col-sm-3 col-md-2' self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6' self.helper.form_text_inline = True self.helper.layout = crispy.Layout( crispy.Fieldset( _("Filter and Download Users"), crispy.Field('role_id', css_class="hqwebapp-select2"), crispy.Field('search_string'), crispy.Field('location_id'), crispy.Field('columns'), ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Download All Users"), type="submit", css_class="btn btn-primary submit_button", )), )
def num_location_restricted_roles(domain): roles = [ r for r in UserRole.by_domain(domain) if not r.permissions.access_all_locations ] return len(roles)
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 = spec_value_to_boolean_or_none(row, 'is_active') is_account_confirmed = spec_value_to_boolean_or_none( row, 'is_account_confirmed') 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 }) # note: explicitly not including "None" here because that's the default value if not set. # False means it was set explicitly to that value if is_account_confirmed is False: raise UserUploadError( _(f"You can only set 'Is Account Confirmed' to 'False' on a new User." )) if is_password(password): user.set_password(password) status_row['flag'] = 'updated' else: kwargs = {} if is_account_confirmed is not None: kwargs['is_account_confirmed'] = is_account_confirmed user = CommCareUser.create(domain, username, password, commit=False, **kwargs) 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
def tearDown(self): for role in UserRole.by_domain(self.linked_domain): role.delete() super(TestUpdateRoles, self).tearDown()
def num_location_restricted_roles(domain): roles = [r for r in UserRole.by_domain(domain) if not r.permissions.access_all_locations] return len(roles)
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
def get_domain_info(domain, upload_domain, user_specs, domain_info_by_domain, upload_user=None, group_memoizer=None, is_web_upload=False): from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView domain_info = domain_info_by_domain.get(domain) if domain_info: return domain_info if domain == upload_domain: domain_group_memoizer = group_memoizer or GroupMemoizer(domain) else: domain_group_memoizer = GroupMemoizer(domain) domain_group_memoizer.load_all() can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS) location_cache = None if can_assign_locations: location_cache = SiteCodeToLocationCache(domain) domain_obj = Domain.get_by_name(domain) allowed_group_names = [ group.name for group in domain_group_memoizer.groups ] profiles_by_name = {} domain_user_specs = [ spec for spec in user_specs if spec.get('domain', upload_domain) == domain ] if is_web_upload: roles_by_name = { role[1]: role[0] for role in get_editable_role_choices( domain, upload_user, allow_admin_role=True) } validators = get_user_import_validators( Domain.get_by_name(domain), domain_user_specs, True, allowed_roles=list(roles_by_name), upload_domain=upload_domain, ) else: roles_by_name = { role.name: role for role in UserRole.by_domain(domain) } definition = CustomDataFieldsDefinition.get(domain, UserFieldsView.field_type) if definition: profiles_by_name = { profile.name: profile for profile in definition.get_profiles() } validators = get_user_import_validators(domain_obj, domain_user_specs, False, allowed_group_names, list(roles_by_name), list(profiles_by_name), upload_domain) domain_info = DomainInfo(validators, can_assign_locations, location_cache, roles_by_name, profiles_by_name, domain_group_memoizer) domain_info_by_domain[domain] = domain_info return domain_info
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
def user_roles(self): user_roles = [AdminUserRole(domain=self.domain)] user_roles.extend(sorted(UserRole.by_domain(self.domain), key=lambda role: role.name if role.name else u'\uFFFF')) return user_roles
def setUpClass(cls): super(AllCommCareUsersTest, cls).setUpClass() delete_all_users() hard_delete_deleted_users() cls.ccdomain = Domain(name='cc_user_domain') cls.ccdomain.save() cls.other_domain = Domain(name='other_domain') cls.other_domain.save() bootstrap_location_types(cls.ccdomain.name) UserRole.init_domain_with_presets(cls.ccdomain.name) cls.user_roles = UserRole.by_domain(cls.ccdomain.name) cls.custom_role = UserRole.get_or_create_with_permissions( cls.ccdomain.name, Permissions( edit_apps=True, edit_web_users=True, view_web_users=True, view_roles=True, ), "Custom Role") cls.custom_role.save() cls.loc1 = make_loc('spain', domain=cls.ccdomain.name, type="district") cls.loc2 = make_loc('madagascar', domain=cls.ccdomain.name, type="district") cls.ccuser_1 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', created_by=None, created_via=None, email='*****@*****.**', ) cls.ccuser_1.set_location(cls.loc1) cls.ccuser_1.save() cls.ccuser_2 = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', created_by=None, created_via=None, email='*****@*****.**', ) cls.ccuser_2.set_role(cls.ccdomain.name, cls.custom_role.get_qualified_id()) cls.ccuser_2.set_location(cls.loc2) cls.ccuser_2.save() cls.web_user = WebUser.create( domain=cls.ccdomain.name, username='******', password='******', created_by=None, created_via=None, email='*****@*****.**', ) cls.ccuser_other_domain = CommCareUser.create( domain=cls.other_domain.name, username='******', password='******', created_by=None, created_via=None, email='*****@*****.**', ) cls.retired_user = CommCareUser.create( domain=cls.ccdomain.name, username='******', password='******', created_by=None, created_via=None, email='*****@*****.**', ) cls.retired_user.retire(deleted_by=None)
def get_user_roles(domain): def _to_json(role): return _clean_json(role.to_json()) return [_to_json(role) for role in UserRole.by_domain(domain)]