Skip to content

Commit

Permalink
Polishing up work on new endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
beeankha committed Jul 18, 2019
1 parent 038092f commit 0dbcf70
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 80 deletions.
12 changes: 9 additions & 3 deletions awx/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3068,7 +3068,7 @@ def validate(self, attrs):
attrs = super(JobRelaunchSerializer, self).validate(attrs)
return attrs

# &&&&&&

class JobCreateScheduleSerializer(BaseSerializer):

can_schedule = serializers.SerializerMethodField()
Expand Down Expand Up @@ -3576,7 +3576,7 @@ class Meta:

def get_related(self, obj):
res = super(WorkflowJobTemplateNodeSerializer, self).get_related(obj)
res['create_approval_job_template'] = self.reverse('api:workflow_job_template_node_create_approval', kwargs={'pk': obj.pk})
res['create_approval_template'] = self.reverse('api:workflow_job_template_node_create_approval', kwargs={'pk': obj.pk})
res['success_nodes'] = self.reverse('api:workflow_job_template_node_success_nodes_list', kwargs={'pk': obj.pk})
res['failure_nodes'] = self.reverse('api:workflow_job_template_node_failure_nodes_list', kwargs={'pk': obj.pk})
res['always_nodes'] = self.reverse('api:workflow_job_template_node_always_nodes_list', kwargs={'pk': obj.pk})
Expand Down Expand Up @@ -3609,6 +3609,9 @@ def validate(self, attrs):
if 'credential' in attrs: # TODO: remove when v2 API is deprecated
deprecated_fields['credential'] = attrs.pop('credential')
view = self.context.get('view')
if attrs.get('unified_job_template') is None:
return {'unified_job_template': None,
'workflow_job_template': attrs.get('workflow_job_template'),}
attrs = super(WorkflowJobTemplateNodeSerializer, self).validate(attrs)
ujt_obj = None
if 'unified_job_template' in attrs:
Expand Down Expand Up @@ -3703,13 +3706,16 @@ def build_relational_field(self, field_name, relation_info):
field_kwargs.pop('queryset', None)
return field_class, field_kwargs

# &&&&&&

class WorkflowJobTemplateNodeCreateApprovalSerializer(BaseSerializer):

class Meta:
model = WorkflowApprovalTemplate
fields = ('timeout', 'name', 'description',)

def to_representation(self, obj):
return {}


class JobListSerializer(JobSerializer, UnifiedJobListSerializer):
pass
Expand Down
2 changes: 1 addition & 1 deletion awx/api/urls/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
url(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
url(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
url(r'^activity_stream/', include(activity_stream_urls)),
url(r'^workflow_approval_templates/', include(workflow_approval_template_urls)), # &&&&&& Take this line out completely?
url(r'^workflow_approval_templates/', include(workflow_approval_template_urls)),
url(r'^workflow_approvals/', include(workflow_approval_urls)),
]

Expand Down
2 changes: 0 additions & 2 deletions awx/api/urls/workflow_approval_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from django.conf.urls import url

from awx.api.views import (
WorkflowApprovalTemplateList,
WorkflowApprovalTemplateDetail,
WorkflowApprovalTemplateJobsList,
WorkflowApprovalTemplateNotificationTemplatesErrorList,
Expand All @@ -14,7 +13,6 @@


urls = [
url(r'^$', WorkflowApprovalTemplateList.as_view(), name='workflow_approval_template_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalTemplateDetail.as_view(), name='workflow_approval_template_detail'),
url(r'^(?P<pk>[0-9]+)/approvals/$', WorkflowApprovalTemplateJobsList.as_view(), name='workflow_approval_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', WorkflowApprovalTemplateNotificationTemplatesStartedList.as_view(),
Expand Down
2 changes: 1 addition & 1 deletion awx/api/urls/workflow_job_template_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobTemplateNodeAlwaysNodesList.as_view(), name='workflow_job_template_node_always_nodes_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
url(r'^(?P<pk>[0-9]+)/create_approval_job_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
url(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
]

__all__ = ['urls']
13 changes: 4 additions & 9 deletions awx/api/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3018,7 +3018,6 @@ class WorkflowJobTemplateNodeCreateApproval(RetrieveAPIView):
model = models.WorkflowJobTemplateNode
serializer_class = serializers.WorkflowJobTemplateNodeCreateApprovalSerializer

# &&&&&&
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if not serializer.is_valid():
Expand Down Expand Up @@ -3597,7 +3596,7 @@ def post(self, request, *args, **kwargs):
headers = {'Location': new_job.get_absolute_url(request=request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)

# &&&&&& Reference

class JobCreateSchedule(RetrieveAPIView):

model = models.Job
Expand Down Expand Up @@ -4422,12 +4421,6 @@ def get_queryset(self):
setattr(this_module, name, view)


class WorkflowApprovalTemplateList(ListCreateAPIView):

model = models.WorkflowApprovalTemplate
serializer_class = serializers.WorkflowApprovalTemplateSerializer


class WorkflowApprovalTemplateDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIView):

model = models.WorkflowApprovalTemplate
Expand Down Expand Up @@ -4481,11 +4474,12 @@ class WorkflowApprovalDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalSerializer

# &&&&&& Include checks in the below two post methods

class WorkflowApprovalApprove(RetrieveAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalViewSerializer

# &&&&&& To address later
def post(self, request, *args, **kwargs):
obj = self.get_object()
obj.approve()
Expand All @@ -4496,6 +4490,7 @@ class WorkflowApprovalDeny(RetrieveAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalViewSerializer

# &&&&&& To address later
def post(self, request, *args, **kwargs):
obj = self.get_object()
obj.deny()
Expand Down
1 change: 0 additions & 1 deletion awx/api/views/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ def get(self, request, format=None):
data['activity_stream'] = reverse('api:activity_stream_list', request=request)
data['workflow_job_templates'] = reverse('api:workflow_job_template_list', request=request)
data['workflow_jobs'] = reverse('api:workflow_job_list', request=request)
data['workflow_approval_templates'] = reverse('api:workflow_approval_template_list', request=request) # &&&&&& Take this line out completely?
data['workflow_approvals'] = reverse('api:workflow_approval_list', request=request)
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
Expand Down
20 changes: 10 additions & 10 deletions awx/main/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -2783,18 +2783,17 @@ def can_use(self, obj):
return True

def filtered_queryset(self):
return self.model.objects.all()
return self.model.objects.filter(
unified_job_node__in=WorkflowJobNode.accessible_pk_qs(
self.user, 'read_role'))

def can_start(self, obj, validate_license=True):
return False
# &&&&&& ??? Start of the RBAC method ???
# &&&&&&
# def can_approve_or_deny(self, obj):
# if self.user.is_superuser: # &&&&&& add "or self.user.approval_role"?
# if self.user.is_superuser: or "self.user.approval_role"?
# return True
# return self.can_change(obj, ????)


# &&&&&& Why is the below not showing up as a class now??
class WorkflowApprovalTemplateAccess(BaseAccess):
'''
I can create approval nodes when:
Expand All @@ -2806,16 +2805,17 @@ class WorkflowApprovalTemplateAccess(BaseAccess):
model = WorkflowApprovalTemplate
prefetch_related = ('created_by', 'modified_by',)

# &&&&&& I need to get the admin role of the WFJT, where WFJT is provided in the key portion vs the data (Alan said that, what does it mean exactly???)
@check_superuser
def can_add(self, data):
if data is None: # Hide direct creation in API browser
return False
return (
self.check_related('workflow_approval_template', UnifiedJobTemplate, role_field='admin_role')
else:
return (self.check_related('workflow_approval_template', UnifiedJobTemplate, role_field='admin_role'))

def filtered_queryset(self):
return self.model.filter(workflowjobtemplatenodes__workflow_job_template=WorkflowJobTemplate.accessible_pk_qs(self.user, 'read_role'))
return self.model.objects.filter(
workflowjobtemplatenodes__workflow_job_template__in=WorkflowJobTemplate.accessible_pk_qs(
self.user, 'read_role'))


for cls in BaseAccess.__subclasses__():
Expand Down
2 changes: 0 additions & 2 deletions awx/main/management/commands/cleanup_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,6 @@ def cleanup_workflow_jobs(self):
skipped += WorkflowJob.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted

# &&&&&& Add cleanup of orphaned approval nodes here?

def cleanup_notifications(self):
skipped, deleted = 0, 0
notifications = Notification.objects.filter(created__lt=self.cutoff)
Expand Down
43 changes: 43 additions & 0 deletions awx/main/migrations/0082_v360_workflowapproval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 2.2.2 on 2019-07-18 14:12

import awx.main.fields
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('main', '0081_v360_notify_on_start'),
]

operations = [
migrations.CreateModel(
name='WorkflowApprovalTemplate',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('timeout', models.IntegerField(blank=True, default=0, help_text='The amount of time (in seconds) before the approval node expires and fails.')),
],
bases=('main.unifiedjobtemplate',),
),
migrations.AddField(
model_name='organization',
name='approval_role',
field=awx.main.fields.ImplicitRoleField(editable=False, null='True', on_delete=django.db.models.deletion.CASCADE, parent_role='admin_role', related_name='+', to='main.Role'),
preserve_default='True',
),
migrations.AddField(
model_name='workflowjobtemplate',
name='approval_role',
field=awx.main.fields.ImplicitRoleField(editable=False, null='True', on_delete=django.db.models.deletion.CASCADE, parent_role=['singleton:system_auditor', 'organization.approval_role', 'admin_role'], related_name='+', to='main.Role'),
preserve_default='True',
),
migrations.CreateModel(
name='WorkflowApproval',
fields=[
('unifiedjob_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('workflow_approval_template', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='approvals', to='main.WorkflowApprovalTemplate')),
],
bases=('main.unifiedjob',),
),
]
2 changes: 1 addition & 1 deletion awx/main/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def o_auth2_token_get_absolute_url(self, request=None):


OAuth2AccessToken.add_to_class('get_absolute_url', o_auth2_token_get_absolute_url)
# &&&&&& "Add model here" - Alan
# &&&&&& Add model here
from awx.main.registrar import activity_stream_registrar # noqa
activity_stream_registrar.connect(Organization)
activity_stream_registrar.connect(Inventory)
Expand Down
1 change: 0 additions & 1 deletion awx/main/models/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ class Meta:
'notification_admin_role', 'credential_admin_role',
'job_template_admin_role',],
)
# &&&&&& The below keeps complaining - fixed by new migration file, perhaps?
approval_role = ImplicitRoleField(
parent_role='admin_role',
)
Expand Down
6 changes: 3 additions & 3 deletions awx/main/models/rbac.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
'read_role': _('Read'),
'update_role': _('Update'),
'use_role': _('Use'),
'approval_role': _('Approve'), # &&&&&& Added this here!
'approval_role': _('Approve'),
}

role_descriptions = {
Expand All @@ -71,7 +71,7 @@
'read_role': _('May view settings for the %s'),
'update_role': _('May update the %s'),
'use_role': _('Can use the %s in a job template'),
'approval_role': _('Can approve or deny a workflow approval node'), # &&&&&& ...and here!
'approval_role': _('Can approve or deny a workflow approval node'),
}


Expand Down Expand Up @@ -482,7 +482,7 @@ def get_roles_on_resource(resource, accessor):
).values_list('role_field', flat=True).distinct()
]

# &&&&&& This area is giving trouble?

def role_summary_fields_generator(content_object, role_field):
global role_descriptions
global role_names
Expand Down
23 changes: 0 additions & 23 deletions awx/main/models/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ class Meta:
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
'organization.auditor_role', 'execute_role', 'admin_role'
])
# &&&&&& The below keeps complaining - fixed by new migration file, perhaps?
approval_role = ImplicitRoleField(parent_role=[
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
'organization.approval_role', 'admin_role',
Expand Down Expand Up @@ -637,28 +636,6 @@ def _get_unified_job_field_names(cls):
def get_absolute_url(self, request=None):
return reverse('api:workflow_approval_template_detail', kwargs={'pk': self.pk}, request=request)

# @property
# def notification_templates(self):
# # Return all notification_templates defined on the Job Template, on the Project, and on the Organization for each trigger type
# base_notification_templates = NotificationTemplate.objects
# error_notification_templates = list(base_notification_templates.filter(
# unifiedjobtemplate_notification_templates_for_errors__in=[self, self.project]))
# started_notification_templates = list(base_notification_templates.filter(
# unifiedjobtemplate_notification_templates_for_started__in=[self, self.project]))
# success_notification_templates = list(base_notification_templates.filter(
# unifiedjobtemplate_notification_templates_for_success__in=[self, self.project]))
# &&&&&& Approvals don't have orgs! How to pull them in? Alan said to "get creative"!
# if self.project is not None and self.project.organization is not None:
# error_notification_templates = set(error_notification_templates + list(base_notification_templates.filter(
# organization_notification_templates_for_errors=self.project.organization)))
# started_notification_templates = set(started_notification_templates + list(base_notification_templates.filter(
# organization_notification_templates_for_started=self.project.organization)))
# success_notification_templates = set(success_notification_templates + list(base_notification_templates.filter(
# organization_notification_templates_for_success=self.project.organization)))
# return dict(error=list(error_notification_templates),
# started=list(started_notification_templates),
# success=list(success_notification_templates))


class WorkflowApproval(UnifiedJob):
class Meta:
Expand Down
2 changes: 1 addition & 1 deletion awx/main/registrar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.db.models.signals import pre_save, post_save, pre_delete, m2m_changed

# &&&&&& Where the signals are hooked up ??

class ActivityStreamRegistrar(object):

def __init__(self):
Expand Down
23 changes: 1 addition & 22 deletions awx/main/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,25 +356,6 @@ def update_host_last_job_after_job_deleted(sender, **kwargs):
_update_host_last_jhs(host)


# &&&&&& Argh. Which one looks better?
# @receiver(pre_delete, sender=Job)
# def delete_detached_approval_nodes(sender, instance, **kwargs):
# for l in instance.labels.all():
# if l.is_candidate_for_detach():
# l.delete()
#
#
# @receiver(pre_delete, sender=Organization)
# def delete_detached_approval_nodes(sender, instance, **kwargs):
# approval_node = ???
# user = get_current_user_or_none()
# for node in approval_node:
# try:
# node.schedule_deletion(user_id=getattr(user, 'id', None))
# except RuntimeError as e:
# logger.debug(e)


# Set via ActivityStreamRegistrar to record activity stream events


Expand Down Expand Up @@ -454,7 +435,7 @@ def model_serializer_mapping():
models.OAuth2Application: serializers.OAuth2ApplicationSerializer,
}

# &&&&&& Can customize how/what the activity stream shows info

def activity_stream_create(sender, instance, created, **kwargs):
if created and activity_stream_enabled:
# TODO: remove deprecated_group conditional in 3.3
Expand Down Expand Up @@ -482,8 +463,6 @@ def activity_stream_create(sender, instance, created, **kwargs):
object1=object1,
changes=json.dumps(changes),
actor=get_current_user_or_none())
# if type(instance) == WorkflowApproval: &&&&&&
# changes['status'] = #???
#TODO: Weird situation where cascade SETNULL doesn't work
# it might actually be a good idea to remove all of these FK references since
# we don't really use them anyway.
Expand Down

0 comments on commit 0dbcf70

Please sign in to comment.