diff --git a/awx/main/access.py b/awx/main/access.py index 1de7049426..2026e8589d 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -353,7 +353,7 @@ class BaseAccess(object): # Shortcuts in certain cases by deferring to earlier property if display_method == 'schedule': - user_capabilities['schedule'] = user_capabilities['edit'] + user_capabilities['schedule'] = user_capabilities['start'] continue elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob)): user_capabilities['delete'] = user_capabilities['edit'] @@ -1912,11 +1912,17 @@ class ScheduleAccess(BaseAccess): @check_superuser def can_add(self, data): - return self.check_related('unified_job_template', UnifiedJobTemplate, data, mandatory=True) + return self.check_related('unified_job_template', UnifiedJobTemplate, data, role_field='execute_role', mandatory=True) @check_superuser def can_change(self, obj, data): - return self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, mandatory=True) + if self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, mandatory=True): + return True + # Users with execute role can modify the schedules they created + return ( + obj.created_by == self.user and + self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, role_field='execute_role', mandatory=True)) + def can_delete(self, obj): return self.can_change(obj, {}) diff --git a/awx/main/tests/functional/test_rbac_job_templates.py b/awx/main/tests/functional/test_rbac_job_templates.py index ac545dafee..13e0da8e8c 100644 --- a/awx/main/tests/functional/test_rbac_job_templates.py +++ b/awx/main/tests/functional/test_rbac_job_templates.py @@ -259,22 +259,37 @@ def test_associate_label(label, user, job_template): @pytest.mark.django_db -def test_move_schedule_to_JT_no_access(job_template, rando): - schedule = Schedule.objects.create( - unified_job_template=job_template, - rrule='DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1') - job_template.admin_role.members.add(rando) - jt2 = JobTemplate.objects.create(name="other-jt") - access = ScheduleAccess(rando) - assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) +class TestJobTemplateSchedules: + + rrule = 'DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' + rrule2 = 'DTSTART:20151117T050000Z RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=1' + + @pytest.fixture + def jt2(self): + return JobTemplate.objects.create(name="other-jt") + + def test_move_schedule_to_JT_no_access(self, job_template, rando, jt2): + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule) + job_template.admin_role.members.add(rando) + access = ScheduleAccess(rando) + assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) -@pytest.mark.django_db -def test_move_schedule_from_JT_no_access(job_template, rando): - schedule = Schedule.objects.create( - unified_job_template=job_template, - rrule='DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1') - jt2 = JobTemplate.objects.create(name="other-jt") - jt2.admin_role.members.add(rando) - access = ScheduleAccess(rando) - assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) + def test_move_schedule_from_JT_no_access(self, job_template, rando, jt2): + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule) + jt2.admin_role.members.add(rando) + access = ScheduleAccess(rando) + assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) + + + def test_can_create_schedule_with_execute(self, job_template, rando): + job_template.execute_role.members.add(rando) + access = ScheduleAccess(rando) + assert access.can_add({'unified_job_template': job_template}) + + + def test_can_modify_ones_own_schedule(self, job_template, rando): + job_template.execute_role.members.add(rando) + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule, created_by=rando) + access = ScheduleAccess(rando) + assert access.can_change(schedule, {'rrule': self.rrule2})