diff --git a/profiles/api/serializers/quota_serializer.py b/profiles/api/serializers/quota_serializer.py index 620c1b829..e76c727a1 100644 --- a/profiles/api/serializers/quota_serializer.py +++ b/profiles/api/serializers/quota_serializer.py @@ -13,8 +13,12 @@ def validate(self, attrs): attrs = super().validate(attrs) scope = self.instance.scope if self.instance else None scope = attrs['scope'] if 'scope' in attrs.keys() else scope - attribute_definition = attrs.get("attribute_definition") - limit = attrs.get("limit") + + attribute_definition = self.instance.attribute_definition if self.instance else None + attribute_definition = attrs['attribute_definition'] if 'attribute_definition' in attrs.keys() else attribute_definition + + limit = self.instance.limit if self.instance else None + limit = attrs['limit'] if 'limit' in attrs.keys() else limit current_quota = Quota.objects.filter(scope=scope, attribute_definition=attribute_definition).first() current_limit = 0 diff --git a/profiles/api/views/quota_api_views.py b/profiles/api/views/quota_api_views.py index 57e2309b8..99cebd242 100644 --- a/profiles/api/views/quota_api_views.py +++ b/profiles/api/views/quota_api_views.py @@ -1,13 +1,49 @@ -from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView +from rest_framework.exceptions import MethodNotAllowed +from rest_framework.permissions import IsAuthenticated + +from Squest.utils.squest_api_views import SquestListCreateAPIView, SquestRetrieveUpdateDestroyAPIView, \ + SquestObjectPermissions from profiles.api.serializers.quota_serializer import QuotaSerializer from profiles.filters.quota import QuotaFilter from profiles.models import Quota +class SquestObjectPermissionsQuota(SquestObjectPermissions): + """ + Custom permission to only allow owners of an object to edit it. + """ + perms_map = { + 'GET': ['%(app_label)s.view_%(model_name)s'], + 'OPTIONS': [], + 'HEAD': [], + 'PUT': ['%(app_label)s.change_%(scope)s_%(model_name)s'], + 'PATCH': ['%(app_label)s.change_%(scope)s_%(model_name)s'], + 'DELETE': ['%(app_label)s.delete_%(model_name)s'], + } + + def get_required_object_permissions(self, method, model_cls, obj=None): + scope = obj.scope + if scope.is_team: + scope_str = "team" + elif scope.is_org: + scope_str = "organization" + kwargs = { + 'app_label': model_cls._meta.app_label, + 'model_name': model_cls._meta.model_name, + 'scope': scope_str + } + + if method not in self.perms_map: + raise MethodNotAllowed(method) + + return [perm % kwargs for perm in self.perms_map[method]] + + class QuotaDetails(SquestRetrieveUpdateDestroyAPIView): serializer_class = QuotaSerializer queryset = Quota.objects.all() + permission_classes = [IsAuthenticated, SquestObjectPermissionsQuota] diff --git a/profiles/apps.py b/profiles/apps.py index ba035bcf3..e799e20a2 100644 --- a/profiles/apps.py +++ b/profiles/apps.py @@ -13,10 +13,10 @@ def create_roles(sender, **kwargs): from profiles.default_rbac.default_roles import default_roles from profiles.models.squest_permission import Permission - role_migration_filter = Role.objects.filter(name="Organization member migration/0014_auto_20230622_1722") + role_migration_filter = Role.objects.filter(name="Squest user migration/0014_auto_20230622_1722") if role_migration_filter.exists(): role_migration = role_migration_filter.first() - role_migration.name = "Organization member" + role_migration.name = "Squest user" role_migration.save() codenames = list( map(lambda default_permissions: default_permissions.split('.')[1], diff --git a/profiles/default_rbac/default_roles.py b/profiles/default_rbac/default_roles.py index c44dab2e8..139713ca7 100644 --- a/profiles/default_rbac/default_roles.py +++ b/profiles/default_rbac/default_roles.py @@ -1,104 +1,42 @@ default_roles = { - "Organization member": { + "Squest user": { "description": "Can view organization", "permissions": [ + "profiles.consume_quota_scope" + "service_catalog.request_on_instance", + "service_catalog.request_on_service", + "profiles.view_organization" - ] - }, - "Team member": { - "description": "Can view team", - "permissions": [ - "profiles.view_team", - ] - }, - "Organization manager": { - "description": "Can view and manage Organization's users.", - "permissions": [ - "profiles.view_organization", - "profiles.view_users_organization", - "profiles.add_users_organization", - "profiles.delete_users_organization", + "profiles.view_team", "profiles.add_team", "profiles.view_team", "profiles.change_team", "profiles.delete_team", + "profiles.view_users_team", "profiles.add_users_team", "profiles.delete_users_team", - ] - }, - "Team manager": { - "description": "Can view and manage Team's users.", - "permissions": [ - "profiles.view_team", - "profiles.view_users_team", - "profiles.add_users_team", - "profiles.delete_users_team", - ] - }, - "Instance viewer": { - "description": "Can view Instance and all related objects.", - "permissions": [ - "service_catalog.view_instance", - "service_catalog.view_request", - "service_catalog.view_requestmessage", - "service_catalog.view_supportmessage", - "service_catalog.view_support", - - ] - }, - "Catalog user": { - "description": "Can request services in catalog", - "permissions": [ - "profiles.consume_quota_scope" - ] - }, - "Instance Operator": { - "description": "Can request services and day 2 operations", - "permissions": [ - "profiles.consume_quota_scope" "service_catalog.view_instance", - "service_catalog.view_request", - "service_catalog.view_requestmessage", - "service_catalog.view_supportmessage", - "service_catalog.view_support", - "service_catalog.request_on_instance", - "service_catalog.request_on_service", + "service_catalog.view_request", "service_catalog.cancel_request", - "service_catalog.add_message", - "service_catalog.view_message", - "service_catalog.change_message", - "service_catalog.delete_message", - - "service_catalog.add_message", - "service_catalog.view_message", - "service_catalog.change_message", - "service_catalog.delete_message", + "service_catalog.view_requestmessage", + "service_catalog.add_requestmessage", + "service_catalog.change_requestmessage", + "service_catalog.view_support", "service_catalog.add_support", "service_catalog.view_support", "service_catalog.change_support", - ] - }, - "Workflow approver": { - "description": "Can approve a step (for Approval Workflow only)", - "permissions": [ - "service_catalog.approve_request_approvalstep", - "service_catalog.view_admin_fill_in_survey" + "service_catalog.view_supportmessage", + "service_catalog.add_supportmessage", + "service_catalog.change_supportmessage", + "profiles.view_quota", ] - }, - "Request approver": { - "description": "Can approve a request", - "permissions": [ - "service_catalog.accept_request", - "service_catalog.view_admin_fill_in_survey" - ] - }, - + } } diff --git a/profiles/migrations/0019_alter_quota_options.py b/profiles/migrations/0019_alter_quota_options.py new file mode 100644 index 000000000..fdbcb50a5 --- /dev/null +++ b/profiles/migrations/0019_alter_quota_options.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.13 on 2023-09-05 14:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0018_auto_20230803_1126'), + ] + + operations = [ + migrations.AlterModelOptions( + name='quota', + options={'default_permissions': ('add', 'delete', 'view', 'list'), 'permissions': [('change_team_quota', 'Can change quota at team level'), ('change_organization_quota', 'Can change quota at organization level')]}, + ), + ] diff --git a/profiles/models/quota.py b/profiles/models/quota.py index a23cfc99e..726dd064a 100644 --- a/profiles/models/quota.py +++ b/profiles/models/quota.py @@ -10,7 +10,12 @@ class Quota(SquestModel): class Meta: unique_together = ('scope', 'attribute_definition') - default_permissions = ('add', 'change', 'delete', 'view', 'list') + default_permissions = ('add', 'delete', 'view', 'list') + + permissions = [ + ("change_team_quota", "Can change quota at team level"), + ("change_organization_quota", "Can change quota at organization level"), + ] scope = ForeignKey("Scope", blank=False, diff --git a/profiles/tables/organization_table.py b/profiles/tables/organization_table.py index 6ad89f9d5..31f436d92 100644 --- a/profiles/tables/organization_table.py +++ b/profiles/tables/organization_table.py @@ -18,9 +18,8 @@ class Meta: def render_users(self, value, record): link = reverse("profiles:organization_details", kwargs={'pk': record.id}) - return format_html(f'<a href="{link}#rbac" class="btn btn-default bg-sm">{record.users.count()}</a>') + return format_html(f'<a href="{link}#users" class="btn btn-default bg-sm">{record.users.count()}</a>') def render_teams(self, value, record): link = reverse("profiles:organization_details", kwargs={'pk': record.id}) return format_html(f'<a href="{link}#teams" class="btn btn-default bg-sm">{record.teams.count()}</a>') - diff --git a/profiles/tables/team_quota_limit_table.py b/profiles/tables/team_quota_limit_table.py index 65a2d5a7c..703617757 100644 --- a/profiles/tables/team_quota_limit_table.py +++ b/profiles/tables/team_quota_limit_table.py @@ -4,11 +4,11 @@ class TeamQuotaLimitTable(Table): - scope = LinkColumn() limit = LinkColumn() + consumed = LinkColumn() class Meta: model = Quota attrs = {"id": "quota_team_table", "class": "table squest-pagination-tables"} - fields = ("scope", "limit") + fields = ("scope", "limit", "consumed") diff --git a/profiles/tables/team_table.py b/profiles/tables/team_table.py index 293d82733..d535cca9b 100644 --- a/profiles/tables/team_table.py +++ b/profiles/tables/team_table.py @@ -19,7 +19,7 @@ class Meta: def render_users(self, value, record): link = reverse("profiles:team_details", kwargs={'pk': record.id}) - return format_html(f'<a href="{link}#rbac" class="btn btn-default bg-sm">{record.users.count()}</a>') + return format_html(f'<a href="{link}#users" class="btn btn-default bg-sm">{record.users.count()}</a>') class TeamUserTable(SquestTable): diff --git a/profiles/templatetags/squest_utils.py b/profiles/templatetags/squest_utils.py index 408dbf604..69f152e34 100644 --- a/profiles/templatetags/squest_utils.py +++ b/profiles/templatetags/squest_utils.py @@ -147,7 +147,7 @@ def generate_sidebar(user): 'name': 'Global permission', 'view_name': 'profiles:globalpermission_rbac', 'icon': 'fas fa-globe', - 'permission_required': 'profiles.can_view_globalpermission', + 'permission_required': 'profiles.view_users_globalpermission', 'active': [ "globalpermission_rbac", "globalpermission_rbac_create", "globalpermission_rbac_delete" ] @@ -176,7 +176,7 @@ def generate_sidebar(user): 'name': 'Users', 'view_name': 'profiles:user_list', 'icon': 'fas fa-user-friends', - 'permission_required': 'profiles.list_team', + 'permission_required': 'profiles.list_user', 'active': [ "user_list", "user_details" ] @@ -280,10 +280,12 @@ def generate_sidebar(user): group_items = list() for view in views: + user_has_perm = False view_data_copy = copy.deepcopy(view) if "treeview_items" not in view: view_permission = view.get('permission_required', None) if (view_permission is None) or (view_permission is not None and user.has_perm(view_permission)): + user_has_perm = True is_group_visible = True else: view_data_copy["active"] = list() @@ -293,11 +295,12 @@ def generate_sidebar(user): view_data_copy["active"] += child_view_data_copy["active"] view_permission = child_view.get('permission_required', None) if (view_permission is None) or (view_permission is not None and user.has_perm(view_permission)): + user_has_perm = True is_group_visible = True child_group.append(child_view_data_copy) view_data_copy["treeview_items"] = child_group - - group_items.append(view_data_copy) + if user_has_perm: + group_items.append(view_data_copy) if is_group_visible: sidebar_menu[group_name] = group_items diff --git a/profiles/views/quota.py b/profiles/views/quota.py index 37dcf00c2..7f56ebfbc 100644 --- a/profiles/views/quota.py +++ b/profiles/views/quota.py @@ -1,3 +1,4 @@ +from django.core.exceptions import ImproperlyConfigured from django.db.models import Sum from django.shortcuts import get_object_or_404 from django_tables2 import RequestConfig @@ -32,7 +33,16 @@ class QuotaEditView(SquestFormView): pk_url_kwarg = "scope_id" def get_permission_required(self): - return f"profiles.change_quota" + object = self.get_object() + if object.is_team: + return "profiles.change_team_quota" + elif object.is_org: + return f"profiles.change_organization_quota" + else: + raise ImproperlyConfigured( + '{0} is missing the permission_required attribute. Define {0}.permission_required, or override ' + '{0}.get_permission_required().'.format(self.__class__.__name__) + ) def get_success_url(self): return self.scope.get_absolute_url() + "#quotas" diff --git a/project-static/squest/js/squest.js b/project-static/squest/js/squest.js index 1eb0987d1..b7a6561da 100644 --- a/project-static/squest/js/squest.js +++ b/project-static/squest/js/squest.js @@ -126,7 +126,7 @@ function add_tab_management() { if (hash) { $('ul#tabs.squest-default-active li.nav-item a[href="' + hash + '"]').trigger('click'); } else { - $("ul#tabs.squest-default-active li.nav-item a:first").trigger("click"); + $("ul#tabs.squest-default-active li.nav-item a:first").tab("show"); } } diff --git a/service_catalog/management/commands/insert_testing_data.py b/service_catalog/management/commands/insert_testing_data.py index 123989db5..24676edf7 100644 --- a/service_catalog/management/commands/insert_testing_data.py +++ b/service_catalog/management/commands/insert_testing_data.py @@ -47,8 +47,7 @@ def handle(self, *args, **options): organization.append(Organization.objects.get_or_create(name=billing_group)[0]) - Organization.objects.get(name="Orchestration").add_user_in_role(User.objects.get(username="Anthony"),Role.objects.get(name="Organization member")) - Organization.objects.get(name="Orchestration").add_user_in_role(User.objects.get(username="Anthony"),Role.objects.get(name="Instance viewer")) + Organization.objects.get(name="Orchestration").add_user_in_role(User.objects.get(username="Anthony"),Role.objects.get(name="Squest user")) job_templates = JobTemplate.objects.all() services = dict() diff --git a/service_catalog/migrations/0014_auto_20230622_1722.py b/service_catalog/migrations/0014_auto_20230622_1722.py index cb1c82064..e58b3e32c 100644 --- a/service_catalog/migrations/0014_auto_20230622_1722.py +++ b/service_catalog/migrations/0014_auto_20230622_1722.py @@ -8,7 +8,7 @@ def billing_group_to_org(apps, schema_editor): Role = apps.get_model('profiles', 'Role') role_org_member, _ = Role.objects.get_or_create( - name="Organization member migration/0014_auto_20230622_1722", + name="Squest user migration/0014_auto_20230622_1722", defaults={'description': 'Can view organization'}, ) BillingGroup = apps.get_model('profiles', 'BillingGroup') diff --git a/templates/profiles/global_permission_default_permission_detail.html b/templates/profiles/global_permission_default_permission_detail.html index e1f206250..e38fe8a58 100644 --- a/templates/profiles/global_permission_default_permission_detail.html +++ b/templates/profiles/global_permission_default_permission_detail.html @@ -18,8 +18,7 @@ <div class="col-12"> <div class="card"> <div class="card-body"> - <div class="alert alert-info alert-dismissible"> - <i class="icon fas fa-info"></i> + <div class="callout callout-info"> List of permissions granted to all users </div> {% render_table default_permissions %} diff --git a/templates/profiles/organization_detail.html b/templates/profiles/organization_detail.html index ecf29f466..270e2e51f 100644 --- a/templates/profiles/organization_detail.html +++ b/templates/profiles/organization_detail.html @@ -8,7 +8,7 @@ {% block extra_header_button %} {% has_perm request.user "profiles.add_users_organization" object as can_add_user_in_organization %} {% has_perm request.user "profiles.add_team" object as can_add_team %} - {% has_perm request.user "profiles.change_quota" object as can_change_quota %} + {% has_perm request.user "profiles.change_organization_quota" object as can_change_quota %} <span {% if not can_change_quota %}title="Permission profiles.change_quota needed"{% endif %}> <a href="{% url 'profiles:organization_quota_edit' object.id %}" class="btn btn-primary{% if not can_change_quota %} disabled{% endif %}"> @@ -73,7 +73,7 @@ <h3 class="card-title"><b>{{ object.name }}</b></h3> </li> {% if users %} <li class="nav-item"> - <a class="nav-link" href="#rbac" title="Role Based Access Control" data-toggle="tab">RBAC</a> + <a class="nav-link" href="#users" data-toggle="tab">Users</a> </li> {% endif %} {% if teams %} @@ -86,9 +86,12 @@ <h3 class="card-title"><b>{{ object.name }}</b></h3> <div class="card-body"> <div class="tab-content"> <div class="tab-pane" id="roles"> + <div class="callout callout-info"> + List of roles granted to all organization users + </div> {% render_table roles %} </div> - <div class="tab-pane" id="rbac"> + <div class="tab-pane" id="users"> {% if users %} {% render_table users %} {% endif %} diff --git a/templates/profiles/team_detail.html b/templates/profiles/team_detail.html index ecdb145d7..5deb314f2 100644 --- a/templates/profiles/team_detail.html +++ b/templates/profiles/team_detail.html @@ -6,7 +6,7 @@ {% load static %} {% block extra_header_button %} {% has_perm request.user "profiles.add_users_team" object as can_add_user %} - {% has_perm request.user "profiles.change_quota" object as can_change_quota %} + {% has_perm request.user "profiles.change_team_quota" object as can_change_quota %} <span {% if not can_change_quota %} title="Permission profiles.change_quota needed" {% endif %}> <a href="{% url 'profiles:team_quota_edit' object.id %}" class="btn btn-primary{% if not can_change_quota %} disabled{% endif %}"> <i @@ -65,8 +65,7 @@ <h3 class="card-title"><b>{{ object.name }}</b></h3> </li> {% if users %} <li class="nav-item"> - <a class="nav-link" href="#rbac" title="Role Based Access Control" - data-toggle="tab">RBAC</a> + <a class="nav-link" href="#users" data-toggle="tab">Users</a> </li> {% endif %} @@ -76,9 +75,12 @@ <h3 class="card-title"><b>{{ object.name }}</b></h3> <div class="card-body"> <div class="tab-content"> <div class="tab-pane" id="roles"> + <div class="callout callout-info"> + List of roles granted to all team users + </div> {% render_table roles %} </div> - <div class="tab-pane" id="rbac"> + <div class="tab-pane" id="users"> {% if users %} {% render_table users %} {% endif %} diff --git a/templates/service_catalog/request_details/approval.html b/templates/service_catalog/request_details/approval.html index e924a47e4..f292357c9 100644 --- a/templates/service_catalog/request_details/approval.html +++ b/templates/service_catalog/request_details/approval.html @@ -4,6 +4,11 @@ {% has_perm request.user "service_catalog.reject_request" object as can_reject_request %} {% has_perm request.user "service_catalog.accept_request" object as can_accept_request %} {% has_perm request.user "service_catalog.process_request" object as can_process_request %} +{% if object.state == "SUBMITTED" %} + <div class="callout callout-info"> + Request is in the approval process + </div> +{% endif %} <div class="timeline"> <div class="time-label"> <span class="bg-info">Submitted</span> @@ -157,7 +162,7 @@ <h3 class="timeline-header">Admin review</h3> {% endwith %} {% if object.state != "NEED_INFO" %} {% with args_filter="need_info,"|addstr:object.id %} - {% if args_filter|can_proceed_request_action and can_process_request %} + {% if args_filter|can_proceed_request_action and can_need_info_request %} <a class="btn btl-lg btn-warning" title="Ask more info" href="{% url 'service_catalog:request_need_info' object.id %}"> @@ -210,30 +215,32 @@ <h3 class="timeline-header">Admin review</h3> <span class="bg-{% if object.state == "ACCEPTED" %}success{% else %}secondary{% endif %}">Accepted</span> </div> {% endif %} - <div> - <i class="fas fa-play fa-lg bg-{% if object.state == "ACCEPTED" %}success{% else %}secondary{% endif %}"></i> - <div class="timeline-item"> + {% if can_process_request %} + <div> + <i class="fas fa-play fa-lg bg-{% if object.state == "ACCEPTED" %}success{% else %}secondary{% endif %}"></i> + <div class="timeline-item"> <span class="time"> <span class="badge bg-secondary"> PENDING </span> </span> - <h3 class="timeline-header">Process the request</h3> - <div class="timeline-body"> - <div class="row justify-content-md-center"> - <div class="timeline-footer"> - {% with args_filter="process,"|addstr:object.id %} - <a class="btn btn-lg btn-success{% if not args_filter|can_proceed_request_action and can_process_request %} disabled{% endif %}" - title="Process" - href="{% url 'service_catalog:request_process' object.id %}"> - <i class="fas fa-play"></i> Process - </a> - {% endwith %} + <h3 class="timeline-header">Process the request</h3> + <div class="timeline-body"> + <div class="row justify-content-md-center"> + <div class="timeline-footer"> + {% with args_filter="process,"|addstr:object.id %} + <a class="btn btn-lg btn-success{% if not args_filter|can_proceed_request_action or not can_process_request %} disabled{% endif %}" + title="Process" + href="{% url 'service_catalog:request_process' object.id %}"> + <i class="fas fa-play"></i> Process + </a> + {% endwith %} + </div> </div> </div> </div> </div> - </div> + {% endif %} <div class="time-label"> <span class="bg-{% if object.state == "COMPLETE" %}success{% else %}secondary{% endif %}">Complete</span> </div> diff --git a/templates/service_catalog/request_details/details_left.html b/templates/service_catalog/request_details/details_left.html index b856544fb..7decf5dbb 100644 --- a/templates/service_catalog/request_details/details_left.html +++ b/templates/service_catalog/request_details/details_left.html @@ -1,4 +1,5 @@ {% has_perm request.user "service_catalog.view_towerserver" object.operation.job_template.tower_server as can_view_towerserver %} +{% has_perm request.user "service_catalog.view_instance" object.instance as can_view_instance %} <div class="card card-{{ object.state |map_request_state }}"> <div class="card-header"> <h3 class="card-title">Request #{{ object.id }}</h3> @@ -9,9 +10,13 @@ <h3 class="card-title">Request #{{ object.id }}</h3> <b>ID</b><span class="float-right">{{ object.id }}</span> </li> <li class="list-group-item"> - <b>Instance</b><a - href="{% url 'service_catalog:instance_details' object.instance.id %}" - class="float-right">{{ object.instance.name }}</a> + <b>Instance</b> + {% if can_view_instance %} + <a href="{% url 'service_catalog:instance_details' object.instance.id %}" + class="float-right">{{ object.instance.name }}</a> + {% else %} + <span class="float-right">{{ object.instance.name }}</span> + {% endif %} </li> <li class="list-group-item"> <b>Service</b><span @@ -25,8 +30,24 @@ <h3 class="card-title">Request #{{ object.id }}</h3> class="float-right text-{{ object.operation.type |map_operation_type }}">{{ object.operation.type }}</strong> </li> <li class="list-group-item"> - <b>Quota scope</b><strong - class="float-right"><a href="{{ object.instance.quota_scope.get_absolute_url }}">{{ object.instance.quota_scope }}</a></strong> + <b>Quota scope</b> + {% if object.instance.quota_scope.is_team %} + {% has_perm request.user "profiles.view_team" object.instance.quota_scope as can_view_quota_scope %} + {% elif object.instance.quota_scope.is_org %} + {% has_perm request.user "profiles.view_org" object.instance.quota_scope as can_view_quota_scope %} + {% endif %} + {% if can_view_quota_scope %} + <strong class="float-right"> + <a + href="{{ object.instance.quota_scope.get_absolute_url }}">{{ object.instance.quota_scope }} + </a> + </strong> + {% else %} + <strong class="float-right"> + <span>{{ object.instance.quota_scope }}</span> + </strong> + {% endif %} + </li> <li class="list-group-item"> <b>Request state</b><strong diff --git a/tests/test_profiles/test_api/test_urls/test_quota.py b/tests/test_profiles/test_api/test_urls/test_quota_org.py similarity index 81% rename from tests/test_profiles/test_api/test_urls/test_quota.py rename to tests/test_profiles/test_api/test_urls/test_quota_org.py index 60bf733c6..ed07d45cc 100644 --- a/tests/test_profiles/test_api/test_urls/test_quota.py +++ b/tests/test_profiles/test_api/test_urls/test_quota_org.py @@ -1,10 +1,12 @@ +from profiles.models import Quota +from resource_tracker_v2.models import AttributeDefinition from tests.permission_endpoint import TestPermissionEndpoint, TestingGetContextView, TestingPostContextView, \ TestingPatchContextView, TestingPutContextView, TestingDeleteContextView from tests.test_profiles.base.base_test_profile import BaseTestProfileAPI -class TestProfilesQuotaPermissionsEndpoint(BaseTestProfileAPI, TestPermissionEndpoint): - def test_quota_views(self): +class TestProfilesQuotaOrganizationPermissionsEndpoint(BaseTestProfileAPI, TestPermissionEndpoint): + def test_quota_organization_views(self): testing_view_list = [ TestingGetContextView( url='api_quota_list_create', @@ -26,7 +28,7 @@ def test_quota_views(self): ), TestingPutContextView( url='api_quota_details', - perm_str='profiles.change_quota', + perm_str='profiles.change_organization_quota', data={ 'scope': self.test_org.id, 'attribute_definition': self.cpu_attribute.id, @@ -36,9 +38,9 @@ def test_quota_views(self): ), TestingPatchContextView( url='api_quota_details', - perm_str='profiles.change_quota', + perm_str='profiles.change_organization_quota', data={ - 'limit': 50 + 'limit': 100 }, url_kwargs={'pk': self.test_quota_org.id} ), diff --git a/tests/test_profiles/test_api/test_urls/test_quota_team.py b/tests/test_profiles/test_api/test_urls/test_quota_team.py new file mode 100644 index 000000000..23626bfc5 --- /dev/null +++ b/tests/test_profiles/test_api/test_urls/test_quota_team.py @@ -0,0 +1,60 @@ +from profiles.models import Quota +from resource_tracker_v2.models import AttributeDefinition +from tests.permission_endpoint import TestPermissionEndpoint, TestingGetContextView, TestingPostContextView, \ + TestingPatchContextView, TestingPutContextView, TestingDeleteContextView +from tests.test_profiles.base.base_test_profile import BaseTestProfileAPI + + +class TestProfilesQuotaTeamPermissionsEndpoint(BaseTestProfileAPI, TestPermissionEndpoint): + def setUp(self): + super().setUp() + + self.attribute_test = AttributeDefinition.objects.create(name="AttributeTest") + Quota.objects.create(scope=self.test_quota_scope_team.org, limit=99999, + attribute_definition=self.attribute_test) + + def test_quota_team_views(self): + testing_view_list = [ + TestingGetContextView( + url='api_quota_list_create', + perm_str='profiles.list_quota', + ), + TestingPostContextView( + url='api_quota_list_create', + perm_str='profiles.add_quota', + data={ + 'scope': self.test_quota_scope_team.id, + 'attribute_definition': self.attribute_test.id, + 'limit': 500 + } + ), + TestingGetContextView( + url='api_quota_details', + perm_str='profiles.view_quota', + url_kwargs={'pk': self.test_quota_team.id} + ), + TestingPutContextView( + url='api_quota_details', + perm_str='profiles.change_team_quota', + data={ + 'scope': self.test_quota_team.scope.id, + 'attribute_definition': self.cpu_attribute.id, + 'limit': 150 + }, + url_kwargs={'pk': self.test_quota_team.id} + ), + TestingPatchContextView( + url='api_quota_details', + perm_str='profiles.change_team_quota', + data={ + 'limit': 50 + }, + url_kwargs={'pk': self.test_quota_team.id} + ), + TestingDeleteContextView( + url='api_quota_details', + perm_str='profiles.delete_quota', + url_kwargs={'pk': self.test_quota_team.id} + ) + ] + self.run_permissions_tests(testing_view_list) diff --git a/tests/test_profiles/test_model/test_scopes.py b/tests/test_profiles/test_model/test_scopes.py index 6e9a843b7..3a586e237 100644 --- a/tests/test_profiles/test_model/test_scopes.py +++ b/tests/test_profiles/test_model/test_scopes.py @@ -9,8 +9,8 @@ class TestModelScope(TransactionTestCase): def setUp(self): - self.role1 = Role.objects.first() - self.role2 = Role.objects.exclude(id=self.role1.id).first() + self.role1 = Role.objects.create(name="role1") + self.role2 = Role.objects.create(name="role2") self.user1 = User.objects.create_user('user1', 'user1@hpe.com', "password") self.user2 = User.objects.create_user('user2', 'user2@hpe.com', "password") super(TestModelScope, self).setUp() diff --git a/tests/test_profiles/test_urls/test_quota.py b/tests/test_profiles/test_urls/test_quota.py index dac81909c..a353030c2 100644 --- a/tests/test_profiles/test_urls/test_quota.py +++ b/tests/test_profiles/test_urls/test_quota.py @@ -16,12 +16,12 @@ def test_quota_views(self): ), TestingGetContextView( url='profiles:organization_quota_edit', - perm_str='profiles.change_quota', + perm_str='profiles.change_organization_quota', url_kwargs={'scope_id': self.test_org.id} ), TestingPostContextView( url='profiles:organization_quota_edit', - perm_str='profiles.change_quota', + perm_str='profiles.change_organization_quota', url_kwargs={'scope_id': self.test_org.id}, data={ f"attribute_definition_{self.cpu_attribute.id}": 100, @@ -30,12 +30,12 @@ def test_quota_views(self): ), TestingGetContextView( url='profiles:team_quota_edit', - perm_str='profiles.change_quota', + perm_str='profiles.change_team_quota', url_kwargs={'scope_id': self.test_quota_scope_team.id} ), TestingPostContextView( url='profiles:team_quota_edit', - perm_str='profiles.change_quota', + perm_str='profiles.change_team_quota', url_kwargs={'scope_id': self.test_quota_scope_team.id}, data={ f"attribute_definition_{self.cpu_attribute.id}": 100, diff --git a/tests/test_service_catalog/base.py b/tests/test_service_catalog/base.py index 96d147462..f8d579436 100644 --- a/tests/test_service_catalog/base.py +++ b/tests/test_service_catalog/base.py @@ -37,7 +37,7 @@ def setUp(self): self.standard_user = User.objects.create_user('stan1234', 'stan.1234@hpe.com', self.common_password) self.standard_user_2 = User.objects.create_user('other1234', 'other.guy@hpe.com', self.common_password) - self.organization_admin_role = Role.objects.get(name="Organization manager") + self.organization_admin_role = Role.objects.create(name="Organization manager") self.team_member_role = Role.objects.create(name="Team member for tests") self.team_member_role.permissions.add( Permission.objects.get_by_natural_key(codename="view_instance", app_label="service_catalog", model="instance"),