Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/cs/SC-3474-cca-permissions-from-…
Browse files Browse the repository at this point in the history
…hq' into autostaging
  • Loading branch information
MartinRiese committed Aug 9, 2024
2 parents 8818112 + 2f85149 commit df2ec81
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 5 deletions.
35 changes: 35 additions & 0 deletions corehq/apps/api/resources/v0_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
log_user_change,
verify_modify_user_conditions,
)
from corehq.apps.users.role_utils import get_commcare_analytics_roles_by_user_domains
from corehq.const import USER_CHANGE_VIA_API
from corehq.util import get_document_or_404
from corehq.util.couch import DocumentNotFound
Expand Down Expand Up @@ -903,6 +904,40 @@ class Meta(object):
include_resource_uri = False


AnalyticsRoles = namedtuple('AnalyticsRoles', 'domain_name role_names')
AnalyticsRoles.__new__.__defaults__ = ('', '')


class CommCareAnalyticsRolesResource(CorsResourceMixin, Resource):
domain_name = fields.CharField(attribute='domain_name', readonly=True)
role_names = fields.CharField(attribute='role_names', readonly=True)

def obj_get_list(self, bundle, **kwargs):
request = bundle.request
roles_by_domain = get_commcare_analytics_roles_by_user_domains(request.couch_user)

domain = request.GET.get('domain')
if domain:
if domain not in roles_by_domain:
return []
return [
AnalyticsRoles(domain, roles_by_domain[domain])
]

results = []
for domain, roles in roles_by_domain.items():
results.append(
AnalyticsRoles(domain, roles)
)
return results

class Meta(object):
resource_name = 'commcare_analytics_roles'
authentication = LoginAuthentication()
list_allowed_methods = ['get']
include_resource_uri = False


Form = namedtuple('Form', 'form_xmlns form_name')
Form.__new__.__defaults__ = ('', '')

Expand Down
1 change: 1 addition & 0 deletions corehq/apps/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ def api_url_patterns():

NON_GLOBAL_USER_API_LIST = (
v0_5.IdentityResource,
v0_5.CommCareAnalyticsRolesResource,
)


Expand Down
10 changes: 10 additions & 0 deletions corehq/apps/users/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
ODATA_FEED_PERMISSION,
}

COMMCARE_ANALYTICS_GAMMA = "gamma"
COMMCARE_ANALYTICS_SQL_LAB = "sql_lab"
COMMCARE_ANALYTICS_DATASET_EDITOR = "dataset_editor"

COMMCARE_ANALYTICS_USER_PERMISSIONS = [
COMMCARE_ANALYTICS_GAMMA,
COMMCARE_ANALYTICS_SQL_LAB,
COMMCARE_ANALYTICS_DATASET_EDITOR,
]

ReportPermission = namedtuple('ReportPermission', ['slug', 'title', 'is_visible'])


Expand Down
18 changes: 18 additions & 0 deletions corehq/apps/users/role_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from corehq.apps.users.models import UserRole, HqPermissions
from corehq.apps.users.permissions import COMMCARE_ANALYTICS_USER_PERMISSIONS
from corehq.toggles import SUPERSET_ANALYTICS


class UserRolePresets:
Expand Down Expand Up @@ -126,3 +128,19 @@ def enable_attendance_coordinator_role_for_domain(domain):
if role.is_archived:
role.is_archived = False
role.save()


def get_commcare_analytics_roles_by_user_domains(couch_user):
enabled_domains = SUPERSET_ANALYTICS.get_enabled_domains()

domain_roles = {}
for domain_membership in couch_user.domain_memberships:
if domain_membership.domain not in enabled_domains:
continue
if domain_membership.is_admin:
analytics_roles = COMMCARE_ANALYTICS_USER_PERMISSIONS
else:
analytics_roles = domain_membership.role.permissions.commcare_analytics_roles_list
domain_roles[domain_membership.domain] = analytics_roles

return domain_roles
84 changes: 82 additions & 2 deletions corehq/apps/users/tests/test_role_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.test import TestCase
from unittest.mock import patch

from corehq.apps.users.models import HqPermissions, UserRole
from corehq.apps.users.models import HqPermissions, UserRole, WebUser, PermissionInfo
from corehq.apps.users.role_utils import (
UserRolePresets,
archive_custom_roles_for_domain,
Expand All @@ -9,8 +10,16 @@
reset_initial_roles_for_domain,
unarchive_roles_for_domain,
enable_attendance_coordinator_role_for_domain,
archive_attendance_coordinator_role_for_domain
archive_attendance_coordinator_role_for_domain,
get_commcare_analytics_roles_by_user_domains,
)
from corehq.apps.domain.shortcuts import create_domain
from corehq.apps.users.permissions import (
COMMCARE_ANALYTICS_USER_PERMISSIONS,
COMMCARE_ANALYTICS_GAMMA,
COMMCARE_ANALYTICS_SQL_LAB,
)
from corehq.toggles import SUPERSET_ANALYTICS


class RoleUtilsTests(TestCase):
Expand Down Expand Up @@ -118,3 +127,74 @@ def _delete_presets(self):
for role in UserRole.objects.get_by_domain(self.domain):
if role.id != self.role1.id:
role.delete()


class TestCommcareAnalyticsRolesByUser(TestCase):

USERNAME = "username"
PASSWORD = "***"

@classmethod
def setUpClass(cls):
cls.domain = create_domain("domain1")
cls.user = WebUser.create("domain1", cls.USERNAME, cls.PASSWORD, None, None)

cls.hq_no_cca_role = cls.create_role("No CCA role", analytics_roles=None)

cls.limited_cca_roles = [
COMMCARE_ANALYTICS_GAMMA,
COMMCARE_ANALYTICS_SQL_LAB,
]
cls.hq_limited_cca_role = cls.create_role("Limited CCA role", analytics_roles=cls.limited_cca_roles)

@classmethod
def tearDownClass(cls):
for role in UserRole.objects.get_by_domain(cls.domain):
role.delete()

cls.user.delete(deleted_by_domain=cls.domain.name, deleted_by=None)
cls.domain.delete()

def test_user_domain_does_not_have_flag_enabled(self):
analytics_roles = get_commcare_analytics_roles_by_user_domains(self.user)
self.assertTrue("domain1" not in analytics_roles)

@patch.object(SUPERSET_ANALYTICS, "get_enabled_domains")
def test_admin_user(self, get_enabled_domains_mock):
get_enabled_domains_mock.return_value = ["domain1"]

self.user.domain_memberships[0].is_admin = True
self.assertTrue(self.user.get_domain_membership("domain1").is_admin)

analytics_roles = get_commcare_analytics_roles_by_user_domains(self.user)
self.assertTrue(analytics_roles["domain1"], COMMCARE_ANALYTICS_USER_PERMISSIONS)

@patch.object(SUPERSET_ANALYTICS, "get_enabled_domains")
def test_non_admin_user(self, get_enabled_domains_mock):
get_enabled_domains_mock.return_value = ["domain1"]

self.user.set_role(self.domain.name, self.hq_no_cca_role.get_qualified_id())
self.assertFalse(self.user.get_domain_membership("domain1").is_admin)

analytics_roles = get_commcare_analytics_roles_by_user_domains(self.user)
self.assertEqual(analytics_roles["domain1"], [])

@patch.object(SUPERSET_ANALYTICS, "get_enabled_domains")
def test_user_has_limited_roles(self, get_enabled_domains_mock):
get_enabled_domains_mock.return_value = ["domain1"]

self.user.set_role(self.domain.name, self.hq_limited_cca_role.get_qualified_id())
self.assertFalse(self.user.get_domain_membership("domain1").is_admin)

analytics_roles = get_commcare_analytics_roles_by_user_domains(self.user)
self.assertEqual(analytics_roles["domain1"], self.limited_cca_roles)

@classmethod
def create_role(cls, role_name, analytics_roles=None):
if analytics_roles is None:
analytics_roles = []
permissions_infos = [PermissionInfo('commcare_analytics_roles', analytics_roles)]
permissions = HqPermissions.from_permission_list(permissions_infos)

role = UserRole.create(domain=cls.domain, name=role_name, permissions=permissions)
return role
11 changes: 8 additions & 3 deletions corehq/apps/users/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@
WorksheetNotFound,
get_workbook,
)
from corehq.apps.users.permissions import (
COMMCARE_ANALYTICS_GAMMA,
COMMCARE_ANALYTICS_SQL_LAB,
COMMCARE_ANALYTICS_DATASET_EDITOR,
)

from dimagi.utils.logging import notify_exception

Expand Down Expand Up @@ -783,15 +788,15 @@ def page_context(self):
def _commcare_analytics_roles_options():
return [
{
'slug': 'gamma',
'slug': COMMCARE_ANALYTICS_GAMMA,
'name': 'Gamma'
},
{
'slug': 'sql_lab',
'slug': COMMCARE_ANALYTICS_SQL_LAB,
'name': 'SQL Lab'
},
{
'slug': 'dataset_editor',
'slug': COMMCARE_ANALYTICS_DATASET_EDITOR,
'name': 'Dataset Editor'
}
]
Expand Down

0 comments on commit df2ec81

Please sign in to comment.