diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 57fea1994b..88bcdbd89f 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1310,10 +1310,12 @@ class ScheduleSerializer(BaseSerializer): def get_related(self, obj): res = super(ScheduleSerializer, self).get_related(obj) res.update(dict( - #unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)), + unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)), )) if obj.unified_job_template and obj.unified_job_template.active: - res['unified_job_template'] = obj.unified_job_template.get_absolute_url() + #TODO: Figure out why we have to do this + ujt = UnifiedJobTemplate.objects.get(id=obj.unified_job_template.id) + res['unified_job_template'] = ujt.get_absolute_url() #obj.unified_job_template.get_absolute_url() return res def validate_rrule(self, attrs, source): diff --git a/awx/api/urls.py b/awx/api/urls.py index 9153e60ad1..1e8bf28da8 100644 --- a/awx/api/urls.py +++ b/awx/api/urls.py @@ -158,6 +158,7 @@ job_event_urls = patterns('awx.api.views', schedule_urls = patterns('awx.api.views', url(r'^$', 'schedule_list'), url(r'^(?P[0-9]+)/$', 'schedule_detail'), + url(r'^(?P[0-9]+)/jobs/$', 'schedule_unified_jobs_list'), ) activity_stream_urls = patterns('awx.api.views', @@ -171,7 +172,7 @@ v1_urls = patterns('awx.api.views', url(r'^authtoken/$', 'auth_token_view'), url(r'^me/$', 'user_me_list'), url(r'^dashboard/$', 'dashboard_view'), - url(r'^schedules/$', include(schedule_urls)), + url(r'^schedules/', include(schedule_urls)), url(r'^organizations/', include(organization_urls)), url(r'^users/', include(user_urls)), url(r'^projects/', include(project_urls)), diff --git a/awx/api/views.py b/awx/api/views.py index bec10a824e..e3c2242a05 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -238,7 +238,7 @@ class DashboardView(APIView): 'total': job_template_list.count()} return Response(data) -class ScheduleList(ListCreateAPIView): +class ScheduleList(ListAPIView): view_name = "Schedules" model = Schedule @@ -251,6 +251,14 @@ class ScheduleDetail(RetrieveUpdateDestroyAPIView): serializer_class = ScheduleSerializer new_in_148 = True +class ScheduleUnifiedJobsList(SubListAPIView): + + model = UnifiedJob + serializer_class = UnifiedJobSerializer + parent_model = Schedule + relationship = '' + view_name = 'Schedule Jobs List' + class AuthTokenView(APIView): authentication_classes = [] diff --git a/awx/main/models/schedules.py b/awx/main/models/schedules.py index 5d3dd3ce3f..14283e1cfe 100644 --- a/awx/main/models/schedules.py +++ b/awx/main/models/schedules.py @@ -23,6 +23,7 @@ class Schedule(CommonModel): class Meta: app_label = 'main' + ordering = ['-next_run'] objects = ScheduleManager() @@ -53,21 +54,24 @@ class Schedule(CommonModel): editable=False, ) - def get_absolute_url(self): - return reverse('api:schedule_list') - #return reverse('api:schedule_detail', args=(self.pk,)) + def __unicode__(self): + return u'%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run) - def update_dt_elements(self): + def get_absolute_url(self): + return reverse('api:schedule_detail', args=(self.pk,)) + + def update_computed_fields(self): future_rs = dateutil.rrule.rrulestr(self.rrule, forceset=True) next_run_actual = future_rs.after(now()) self.next_run = next_run_actual if self.dtstart is None: self.dtstart = self.next_run - if "until" in self.rrule.lower() or 'count' in self.rrule.lower(): + if self.dtend is None and "until" in self.rrule.lower() or 'count' in self.rrule.lower(): self.dtend = future_rs[-1] + self.unified_job_template.update_computed_fields() def save(self, *args, **kwargs): - self.update_dt_elements() + # Check if new rrule, if so set dtstart and dtend to null + self.update_computed_fields() super(Schedule, self).save(*args, **kwargs) - # update template next run details diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 7cc6fb1259..c6d868edf0 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -135,6 +135,13 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique): def last_updated(self): return self.last_job_run + def update_computed_fields(self): + related_schedules = Schedule.objects.get(enabled=True, unified_job_template=self, next_run__isnull=False).order_by('-next_run') + if related_schedules.exists(): + self.next_schedule = related_schedules[0] + self.next_job_run = related_schedules[0].next_run + self.save(update_fields=['next_schedule', 'next_job_run']) + def save(self, *args, **kwargs): # If update_fields has been specified, add our field names to it, # if it hasn't been specified, then we're just doing a normal save.