diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 4f57087599..381883b81d 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1246,7 +1246,7 @@ class OrganizationSerializer(BaseSerializer): applications = self.reverse('api:organization_applications_list', kwargs={'pk': obj.pk}), activity_stream = self.reverse('api:organization_activity_stream_list', kwargs={'pk': obj.pk}), notification_templates = self.reverse('api:organization_notification_templates_list', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:organization_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:organization_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:organization_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:organization_notification_templates_error_list', kwargs={'pk': obj.pk}), object_roles = self.reverse('api:organization_object_roles_list', kwargs={'pk': obj.pk}), @@ -1352,7 +1352,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer): scm_inventory_sources = self.reverse('api:project_scm_inventory_sources', kwargs={'pk': obj.pk}), schedules = self.reverse('api:project_schedules_list', kwargs={'pk': obj.pk}), activity_stream = self.reverse('api:project_activity_stream_list', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:project_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:project_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:project_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:project_notification_templates_error_list', kwargs={'pk': obj.pk}), access_list = self.reverse('api:project_access_list', kwargs={'pk': obj.pk}), @@ -1970,7 +1970,7 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt activity_stream = self.reverse('api:inventory_source_activity_stream_list', kwargs={'pk': obj.pk}), hosts = self.reverse('api:inventory_source_hosts_list', kwargs={'pk': obj.pk}), groups = self.reverse('api:inventory_source_groups_list', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:inventory_source_notification_templates_error_list', kwargs={'pk': obj.pk}), )) @@ -2792,7 +2792,7 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO schedules = self.reverse('api:job_template_schedules_list', kwargs={'pk': obj.pk}), activity_stream = self.reverse('api:job_template_activity_stream_list', kwargs={'pk': obj.pk}), launch = self.reverse('api:job_template_launch', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:job_template_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:job_template_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:job_template_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:job_template_notification_templates_error_list', kwargs={'pk': obj.pk}), access_list = self.reverse('api:job_template_access_list', kwargs={'pk': obj.pk}), @@ -3204,7 +3204,7 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer): jobs = self.reverse('api:system_job_template_jobs_list', kwargs={'pk': obj.pk}), schedules = self.reverse('api:system_job_template_schedules_list', kwargs={'pk': obj.pk}), launch = self.reverse('api:system_job_template_launch', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:system_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:system_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:system_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}), @@ -3271,7 +3271,7 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo workflow_nodes = self.reverse('api:workflow_job_template_workflow_nodes_list', kwargs={'pk': obj.pk}), labels = self.reverse('api:workflow_job_template_label_list', kwargs={'pk': obj.pk}), activity_stream = self.reverse('api:workflow_job_template_activity_stream_list', kwargs={'pk': obj.pk}), - notification_templates_any = self.reverse('api:workflow_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}), + notification_templates_started = self.reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}), notification_templates_success = self.reverse('api:workflow_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}), notification_templates_error = self.reverse('api:workflow_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}), access_list = self.reverse('api:workflow_job_template_access_list', kwargs={'pk': obj.pk}), diff --git a/awx/api/urls/inventory_source.py b/awx/api/urls/inventory_source.py index 7a03b91f76..736797c5a7 100644 --- a/awx/api/urls/inventory_source.py +++ b/awx/api/urls/inventory_source.py @@ -13,8 +13,8 @@ from awx.api.views import ( InventorySourceCredentialsList, InventorySourceGroupsList, InventorySourceHostsList, - InventorySourceNotificationTemplatesAnyList, InventorySourceNotificationTemplatesErrorList, + InventorySourceNotificationTemplatesStartedList, InventorySourceNotificationTemplatesSuccessList, ) @@ -29,8 +29,8 @@ urls = [ url(r'^(?P[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'), url(r'^(?P[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'), url(r'^(?P[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', InventorySourceNotificationTemplatesAnyList.as_view(), - name='inventory_source_notification_templates_any_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', InventorySourceNotificationTemplatesStartedList.as_view(), + name='inventory_source_notification_templates_started_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', InventorySourceNotificationTemplatesErrorList.as_view(), name='inventory_source_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', InventorySourceNotificationTemplatesSuccessList.as_view(), diff --git a/awx/api/urls/job_template.py b/awx/api/urls/job_template.py index 0b43575ba4..922019d117 100644 --- a/awx/api/urls/job_template.py +++ b/awx/api/urls/job_template.py @@ -13,8 +13,8 @@ from awx.api.views import ( JobTemplateSchedulesList, JobTemplateSurveySpec, JobTemplateActivityStreamList, - JobTemplateNotificationTemplatesAnyList, JobTemplateNotificationTemplatesErrorList, + JobTemplateNotificationTemplatesStartedList, JobTemplateNotificationTemplatesSuccessList, JobTemplateInstanceGroupsList, JobTemplateAccessList, @@ -34,8 +34,8 @@ urls = [ url(r'^(?P[0-9]+)/schedules/$', JobTemplateSchedulesList.as_view(), name='job_template_schedules_list'), url(r'^(?P[0-9]+)/survey_spec/$', JobTemplateSurveySpec.as_view(), name='job_template_survey_spec'), url(r'^(?P[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', JobTemplateNotificationTemplatesAnyList.as_view(), - name='job_template_notification_templates_any_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', JobTemplateNotificationTemplatesStartedList.as_view(), + name='job_template_notification_templates_started_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', JobTemplateNotificationTemplatesErrorList.as_view(), name='job_template_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', JobTemplateNotificationTemplatesSuccessList.as_view(), diff --git a/awx/api/urls/organization.py b/awx/api/urls/organization.py index 911143bb86..952209423e 100644 --- a/awx/api/urls/organization.py +++ b/awx/api/urls/organization.py @@ -15,8 +15,8 @@ from awx.api.views import ( OrganizationCredentialList, OrganizationActivityStreamList, OrganizationNotificationTemplatesList, - OrganizationNotificationTemplatesAnyList, OrganizationNotificationTemplatesErrorList, + OrganizationNotificationTemplatesStartedList, OrganizationNotificationTemplatesSuccessList, OrganizationInstanceGroupsList, OrganizationObjectRolesList, @@ -25,7 +25,7 @@ from awx.api.views import ( ) -urls = [ +urls = [ url(r'^$', OrganizationList.as_view(), name='organization_list'), url(r'^(?P[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'), url(r'^(?P[0-9]+)/users/$', OrganizationUsersList.as_view(), name='organization_users_list'), @@ -37,8 +37,8 @@ urls = [ url(r'^(?P[0-9]+)/credentials/$', OrganizationCredentialList.as_view(), name='organization_credential_list'), url(r'^(?P[0-9]+)/activity_stream/$', OrganizationActivityStreamList.as_view(), name='organization_activity_stream_list'), url(r'^(?P[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', OrganizationNotificationTemplatesAnyList.as_view(), - name='organization_notification_templates_any_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', OrganizationNotificationTemplatesStartedList.as_view(), + name='organization_notification_templates_started_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', OrganizationNotificationTemplatesErrorList.as_view(), name='organization_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', OrganizationNotificationTemplatesSuccessList.as_view(), diff --git a/awx/api/urls/project.py b/awx/api/urls/project.py index 263014e6e2..c0909873df 100644 --- a/awx/api/urls/project.py +++ b/awx/api/urls/project.py @@ -14,8 +14,8 @@ from awx.api.views import ( ProjectUpdatesList, ProjectActivityStreamList, ProjectSchedulesList, - ProjectNotificationTemplatesAnyList, ProjectNotificationTemplatesErrorList, + ProjectNotificationTemplatesStartedList, ProjectNotificationTemplatesSuccessList, ProjectObjectRolesList, ProjectAccessList, @@ -34,10 +34,11 @@ urls = [ url(r'^(?P[0-9]+)/project_updates/$', ProjectUpdatesList.as_view(), name='project_updates_list'), url(r'^(?P[0-9]+)/activity_stream/$', ProjectActivityStreamList.as_view(), name='project_activity_stream_list'), url(r'^(?P[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', ProjectNotificationTemplatesAnyList.as_view(), name='project_notification_templates_any_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', ProjectNotificationTemplatesSuccessList.as_view(), name='project_notification_templates_success_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', ProjectNotificationTemplatesStartedList.as_view(), + name='project_notification_templates_started_list'), url(r'^(?P[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'), url(r'^(?P[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'), url(r'^(?P[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'), diff --git a/awx/api/urls/system_job_template.py b/awx/api/urls/system_job_template.py index 637ce05060..396271417d 100644 --- a/awx/api/urls/system_job_template.py +++ b/awx/api/urls/system_job_template.py @@ -9,8 +9,8 @@ from awx.api.views import ( SystemJobTemplateLaunch, SystemJobTemplateJobsList, SystemJobTemplateSchedulesList, - SystemJobTemplateNotificationTemplatesAnyList, SystemJobTemplateNotificationTemplatesErrorList, + SystemJobTemplateNotificationTemplatesStartedList, SystemJobTemplateNotificationTemplatesSuccessList, ) @@ -21,8 +21,8 @@ urls = [ url(r'^(?P[0-9]+)/launch/$', SystemJobTemplateLaunch.as_view(), name='system_job_template_launch'), url(r'^(?P[0-9]+)/jobs/$', SystemJobTemplateJobsList.as_view(), name='system_job_template_jobs_list'), url(r'^(?P[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', SystemJobTemplateNotificationTemplatesAnyList.as_view(), - name='system_job_template_notification_templates_any_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', SystemJobTemplateNotificationTemplatesStartedList.as_view(), + name='system_job_template_notification_templates_started_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', SystemJobTemplateNotificationTemplatesErrorList.as_view(), name='system_job_template_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', SystemJobTemplateNotificationTemplatesSuccessList.as_view(), diff --git a/awx/api/urls/workflow_job_template.py b/awx/api/urls/workflow_job_template.py index 2c6f880ce5..0a33a8eaaa 100644 --- a/awx/api/urls/workflow_job_template.py +++ b/awx/api/urls/workflow_job_template.py @@ -13,8 +13,8 @@ from awx.api.views import ( WorkflowJobTemplateSurveySpec, WorkflowJobTemplateWorkflowNodesList, WorkflowJobTemplateActivityStreamList, - WorkflowJobTemplateNotificationTemplatesAnyList, WorkflowJobTemplateNotificationTemplatesErrorList, + WorkflowJobTemplateNotificationTemplatesStartedList, WorkflowJobTemplateNotificationTemplatesSuccessList, WorkflowJobTemplateAccessList, WorkflowJobTemplateObjectRolesList, @@ -32,8 +32,8 @@ urls = [ url(r'^(?P[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'), url(r'^(?P[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'), url(r'^(?P[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'), - url(r'^(?P[0-9]+)/notification_templates_any/$', WorkflowJobTemplateNotificationTemplatesAnyList.as_view(), - name='workflow_job_template_notification_templates_any_list'), + url(r'^(?P[0-9]+)/notification_templates_started/$', WorkflowJobTemplateNotificationTemplatesStartedList.as_view(), + name='workflow_job_template_notification_templates_started_list'), url(r'^(?P[0-9]+)/notification_templates_error/$', WorkflowJobTemplateNotificationTemplatesErrorList.as_view(), name='workflow_job_template_notification_templates_error_list'), url(r'^(?P[0-9]+)/notification_templates_success/$', WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(), diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 9f85854cdd..092675267d 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -116,6 +116,7 @@ from awx.api.views.organization import ( # noqa OrganizationNotificationTemplatesList, OrganizationNotificationTemplatesAnyList, OrganizationNotificationTemplatesErrorList, + OrganizationNotificationTemplatesStartedList, OrganizationNotificationTemplatesSuccessList, OrganizationInstanceGroupsList, OrganizationAccessList, @@ -747,22 +748,20 @@ class ProjectNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView): model = models.NotificationTemplate serializer_class = serializers.NotificationTemplateSerializer parent_model = models.Project - relationship = 'notification_templates_any' -class ProjectNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView): +class ProjectNotificationTemplatesStartedList(ProjectNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + +class ProjectNotificationTemplatesErrorList(ProjectNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.Project relationship = 'notification_templates_error' -class ProjectNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView): +class ProjectNotificationTemplatesSuccessList(ProjectNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.Project relationship = 'notification_templates_success' @@ -2102,7 +2101,6 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi model = models.NotificationTemplate serializer_class = serializers.NotificationTemplateSerializer parent_model = models.InventorySource - relationship = 'notification_templates_any' def post(self, request, *args, **kwargs): parent = self.get_parent_object() @@ -2113,6 +2111,11 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi return super(InventorySourceNotificationTemplatesAnyList, self).post(request, *args, **kwargs) +class InventorySourceNotificationTemplatesStartedList(InventorySourceNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + class InventorySourceNotificationTemplatesErrorList(InventorySourceNotificationTemplatesAnyList): relationship = 'notification_templates_error' @@ -2626,22 +2629,20 @@ class JobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView): model = models.NotificationTemplate serializer_class = serializers.NotificationTemplateSerializer parent_model = models.JobTemplate - relationship = 'notification_templates_any' -class JobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView): +class JobTemplateNotificationTemplatesStartedList(JobTemplateNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + +class JobTemplateNotificationTemplatesErrorList(JobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.JobTemplate relationship = 'notification_templates_error' -class JobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView): +class JobTemplateNotificationTemplatesSuccessList(JobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.JobTemplate relationship = 'notification_templates_success' @@ -3234,22 +3235,20 @@ class WorkflowJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachA model = models.NotificationTemplate serializer_class = serializers.NotificationTemplateSerializer parent_model = models.WorkflowJobTemplate - relationship = 'notification_templates_any' -class WorkflowJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView): +class WorkflowJobTemplateNotificationTemplatesStartedList(WorkflowJobTemplateNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + +class WorkflowJobTemplateNotificationTemplatesErrorList(WorkflowJobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.WorkflowJobTemplate relationship = 'notification_templates_error' -class WorkflowJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView): +class WorkflowJobTemplateNotificationTemplatesSuccessList(WorkflowJobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.WorkflowJobTemplate relationship = 'notification_templates_success' @@ -3411,22 +3410,20 @@ class SystemJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPI model = models.NotificationTemplate serializer_class = serializers.NotificationTemplateSerializer parent_model = models.SystemJobTemplate - relationship = 'notification_templates_any' -class SystemJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView): +class SystemJobTemplateNotificationTemplatesStartedList(SystemJobTemplateNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + +class SystemJobTemplateNotificationTemplatesErrorList(SystemJobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.SystemJobTemplate relationship = 'notification_templates_error' -class SystemJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView): +class SystemJobTemplateNotificationTemplatesSuccessList(SystemJobTemplateNotificationTemplatesAnyList): - model = models.NotificationTemplate - serializer_class = serializers.NotificationTemplateSerializer - parent_model = models.SystemJobTemplate relationship = 'notification_templates_success' diff --git a/awx/api/views/organization.py b/awx/api/views/organization.py index 37cce7d289..6213e14f63 100644 --- a/awx/api/views/organization.py +++ b/awx/api/views/organization.py @@ -178,22 +178,20 @@ class OrganizationNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView) model = NotificationTemplate serializer_class = NotificationTemplateSerializer parent_model = Organization - relationship = 'notification_templates_any' -class OrganizationNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView): +class OrganizationNotificationTemplatesStartedList(OrganizationNotificationTemplatesAnyList): + + relationship = 'notification_templates_started' + + +class OrganizationNotificationTemplatesErrorList(OrganizationNotificationTemplatesAnyList): - model = NotificationTemplate - serializer_class = NotificationTemplateSerializer - parent_model = Organization relationship = 'notification_templates_error' -class OrganizationNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView): +class OrganizationNotificationTemplatesSuccessList(OrganizationNotificationTemplatesAnyList): - model = NotificationTemplate - serializer_class = NotificationTemplateSerializer - parent_model = Organization relationship = 'notification_templates_success' diff --git a/awx/main/migrations/0081_v360_notify_on_start.py b/awx/main/migrations/0081_v360_notify_on_start.py new file mode 100644 index 0000000000..4240905f40 --- /dev/null +++ b/awx/main/migrations/0081_v360_notify_on_start.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-30 20:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def forwards_split_unified_job_template_any(apps, schema_editor): + UnifiedJobTemplate = apps.get_model('main', 'unifiedjobtemplate') + for ujt in UnifiedJobTemplate.objects.all(): + for ujt_notification in ujt.notification_templates_any.all(): + ujt.notification_templates_success.add(ujt_notification) + ujt.notification_templates_error.add(ujt_notification) + +def forwards_split_organization_any(apps, schema_editor): + Organization = apps.get_model('main', 'organization') + for org in Organization.objects.all(): + for org_notification in org.notification_templates_any.all(): + org.notification_templates_success.add(org_notification) + org.notification_templates_error.add(org_notification) + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0080_v360_replace_job_origin'), + ] + + operations = [ + migrations.AddField( + model_name='organization', + name='notification_templates_started', + field=models.ManyToManyField(blank=True, related_name='organization_notification_templates_for_started', to='main.NotificationTemplate'), + ), + migrations.AddField( + model_name='unifiedjobtemplate', + name='notification_templates_started', + field=models.ManyToManyField(blank=True, related_name='unifiedjobtemplate_notification_templates_for_started', to='main.NotificationTemplate'), + ), + # Separate out "any" notifications into "success" and "error" before the "any" state gets deleted. + migrations.RunPython(forwards_split_unified_job_template_any, forwards_split_organization_any), + migrations.RemoveField( + model_name='organization', + name='notification_templates_any', + ), + migrations.RemoveField( + model_name='unifiedjobtemplate', + name='notification_templates_any', + ), + ] diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index 5671bb3383..287955f42e 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -163,18 +163,18 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin): all_orgs.add(h.inventory.organization) active_templates = dict(error=set(), success=set(), - any=set()) + started=set()) base_notification_templates = NotificationTemplate.objects for org in all_orgs: for templ in base_notification_templates.filter(organization_notification_templates_for_errors=org): active_templates['error'].add(templ) for templ in base_notification_templates.filter(organization_notification_templates_for_success=org): active_templates['success'].add(templ) - for templ in base_notification_templates.filter(organization_notification_templates_for_any=org): - active_templates['any'].add(templ) + for templ in base_notification_templates.filter(organization_notification_templates_for_started=org): + active_templates['started'].add(templ) active_templates['error'] = list(active_templates['error']) - active_templates['any'] = list(active_templates['any']) active_templates['success'] = list(active_templates['success']) + active_templates['started'] = list(active_templates['started']) return active_templates def get_passwords_needed_to_start(self): diff --git a/awx/main/models/base.py b/awx/main/models/base.py index ba44f9aa98..9925dc6049 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -386,14 +386,13 @@ class NotificationFieldsModel(BaseModel): related_name='%(class)s_notification_templates_for_success' ) - notification_templates_any = models.ManyToManyField( + notification_templates_started = models.ManyToManyField( "NotificationTemplate", blank=True, - related_name='%(class)s_notification_templates_for_any' + related_name='%(class)s_notification_templates_for_started' ) - def prevent_search(relation): """ Used to mark a model field or relation as "restricted from filtering" diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index e7244bac5b..5c1f4ef8eb 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -1619,20 +1619,20 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualE base_notification_templates = NotificationTemplate.objects error_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_errors__in=[self])) + started_notification_templates = list(base_notification_templates + .filter(unifiedjobtemplate_notification_templates_for_started__in=[self])) success_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_success__in=[self])) - any_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_any__in=[self])) if self.inventory.organization is not None: error_notification_templates = set(error_notification_templates + list(base_notification_templates .filter(organization_notification_templates_for_errors=self.inventory.organization))) + started_notification_templates = set(started_notification_templates + list(base_notification_templates + .filter(organization_notification_templates_for_started=self.inventory.organization))) success_notification_templates = set(success_notification_templates + list(base_notification_templates .filter(organization_notification_templates_for_success=self.inventory.organization))) - any_notification_templates = set(any_notification_templates + list(base_notification_templates - .filter(organization_notification_templates_for_any=self.inventory.organization))) return dict(error=list(error_notification_templates), - success=list(success_notification_templates), - any=list(any_notification_templates)) + started=list(started_notification_templates), + success=list(success_notification_templates)) def clean_source(self): # TODO: remove in 3.3 source = self.source diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index b8f2661c97..59b26c66e5 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -435,19 +435,21 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour 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])) - any_notification_templates = list(base_notification_templates.filter( - unifiedjobtemplate_notification_templates_for_any__in=[self, self.project])) # Get Organization NotificationTemplates 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))) - any_notification_templates = set(any_notification_templates + list(base_notification_templates.filter( - organization_notification_templates_for_any=self.project.organization))) - return dict(error=list(error_notification_templates), success=list(success_notification_templates), any=list(any_notification_templates)) + return dict(error=list(error_notification_templates), + started=list(started_notification_templates), + success=list(success_notification_templates)) ''' RelatedJobsMixin @@ -1133,13 +1135,13 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions): base_notification_templates = NotificationTemplate.objects.all() error_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_errors__in=[self])) + started_notification_templates = list(base_notification_templates + .filter(unifiedjobtemplate_notification_templates_for_started__in=[self])) success_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_success__in=[self])) - any_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_any__in=[self])) return dict(error=list(error_notification_templates), - success=list(success_notification_templates), - any=list(any_notification_templates)) + started=list(started_notification_templates), + success=list(success_notification_templates)) def _accept_or_ignore_job_kwargs(self, _exclude_errors=None, **kwargs): extra_data = kwargs.pop('extra_vars', {}) diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py index 9fa6e31b17..cdec14f953 100644 --- a/awx/main/models/notifications.py +++ b/awx/main/models/notifications.py @@ -7,6 +7,7 @@ import logging from django.db import models from django.conf import settings from django.core.mail.message import EmailMessage +from django.db import connection from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import smart_str, force_text @@ -129,7 +130,7 @@ class NotificationTemplate(CommonModelNameNotUnique): if field not in notification_configuration: if 'default' in params: notification_configuration[field] = params['default'] - backend_obj = self.notification_class(**notification_configuration) + backend_obj = self.notification_class(**notification_configuration) notification_obj = EmailMessage(subject, backend_obj.format_body(body), sender, recipients) with set_environ(**settings.AWX_TASK_ENV): return backend_obj.send_messages([notification_obj]) @@ -221,10 +222,13 @@ class JobNotificationMixin(object): def build_notification_failed_message(self): return self._build_notification_message('failed') + def build_notification_running_message(self): + return self._build_notification_message('running') + def send_notification_templates(self, status_str): from awx.main.tasks import send_notifications # avoid circular import - if status_str not in ['succeeded', 'failed']: - raise ValueError(_("status_str must be either succeeded or failed")) + if status_str not in ['succeeded', 'failed', 'running']: + raise ValueError(_("status_str must be either running, succeeded or failed")) try: notification_templates = self.get_notification_templates() except Exception: @@ -233,14 +237,19 @@ class JobNotificationMixin(object): if notification_templates: if status_str == 'succeeded': notification_template_type = 'success' + elif status_str == 'running': + notification_template_type = 'started' else: notification_template_type = 'error' - all_notification_templates = set(notification_templates.get(notification_template_type, []) + notification_templates.get('any', [])) + all_notification_templates = set(notification_templates.get(notification_template_type, [])) if len(all_notification_templates): try: (notification_subject, notification_body) = getattr(self, 'build_notification_%s_message' % status_str)() except AttributeError: raise NotImplementedError("build_notification_%s_message() does not exist" % status_str) - send_notifications.delay([n.generate_notification(notification_subject, notification_body).id - for n in all_notification_templates], - job_id=self.id) + + def send_it(): + send_notifications.delay([n.generate_notification(notification_subject, notification_body).id + for n in all_notification_templates], + job_id=self.id) + connection.on_commit(send_it) diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index 1759375b51..c86b08421d 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -411,24 +411,24 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn base_notification_templates = NotificationTemplate.objects error_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_errors=self)) + started_notification_templates = list(base_notification_templates + .filter(unifiedjobtemplate_notification_templates_for_started=self)) success_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_success=self)) - any_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_any=self)) # Get Organization NotificationTemplates if self.organization is not None: error_notification_templates = set(error_notification_templates + list(base_notification_templates .filter(organization_notification_templates_for_errors=self.organization))) + started_notification_templates = set(started_notification_templates + + list(base_notification_templates + .filter(organization_notification_templates_for_started=self.organization))) success_notification_templates = set(success_notification_templates + list(base_notification_templates .filter(organization_notification_templates_for_success=self.organization))) - any_notification_templates = set(any_notification_templates + - list(base_notification_templates - .filter(organization_notification_templates_for_any=self.organization))) return dict(error=list(error_notification_templates), - success=list(success_notification_templates), - any=list(any_notification_templates)) + started=list(started_notification_templates), + success=list(success_notification_templates)) def get_absolute_url(self, request=None): return reverse('api:project_detail', kwargs={'pk': self.pk}, request=request) @@ -567,5 +567,3 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin, TaskManage if not selected_groups: return self.global_instance_groups return selected_groups - - diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index 4e4f2a8dbb..e5f36054ff 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -419,13 +419,13 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl base_notification_templates = NotificationTemplate.objects.all() error_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_errors__in=[self])) + started_notification_templates = list(base_notification_templates + .filter(unifiedjobtemplate_notification_templates_for_started__in=[self])) success_notification_templates = list(base_notification_templates .filter(unifiedjobtemplate_notification_templates_for_success__in=[self])) - any_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_any__in=[self])) return dict(error=list(error_notification_templates), - success=list(success_notification_templates), - any=list(any_notification_templates)) + started=list(started_notification_templates), + success=list(success_notification_templates)) def create_unified_job(self, **kwargs): workflow_job = super(WorkflowJobTemplate, self).create_unified_job(**kwargs) diff --git a/awx/main/scheduler/task_manager.py b/awx/main/scheduler/task_manager.py index e0d595559f..b79abbad0d 100644 --- a/awx/main/scheduler/task_manager.py +++ b/awx/main/scheduler/task_manager.py @@ -193,6 +193,8 @@ class TaskManager(): status_changed = True if status_changed: workflow_job.websocket_emit_status(workflow_job.status) + # Operations whose queries rely on modifications made during the atomic scheduling session + workflow_job.send_notification_templates('succeeded' if workflow_job.status == 'successful' else 'failed') if workflow_job.spawned_by_workflow: schedule_task_manager() return result @@ -233,6 +235,7 @@ class TaskManager(): else: if type(task) is WorkflowJob: task.status = 'running' + task.send_notification_templates('running') logger.debug('Transitioning %s to running status.', task.log_format) schedule_task_manager() elif not task.supports_isolation() and rampart_group.controller_id: @@ -581,10 +584,5 @@ class TaskManager(): logger.debug("Not running scheduler, another task holds lock") return logger.debug("Starting Scheduler") - with task_manager_bulk_reschedule(): - finished_wfjs = self._schedule() - - # Operations whose queries rely on modifications made during the atomic scheduling session - for wfj in WorkflowJob.objects.filter(id__in=finished_wfjs): - wfj.send_notification_templates('succeeded' if wfj.status == 'successful' else 'failed') + self._schedule() diff --git a/awx/main/tasks.py b/awx/main/tasks.py index f899fadb05..d73737a4b3 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1131,6 +1131,7 @@ class BaseTask(object): try: isolated = self.instance.is_isolated() + self.instance.send_notification_templates("running") self.pre_run_hook(self.instance) if self.instance.cancel_flag: self.instance = self.update_model(self.instance.pk, status='canceled') diff --git a/awx/main/tests/docs/test_swagger_generation.py b/awx/main/tests/docs/test_swagger_generation.py index 9f00193515..5ee30e0b1e 100644 --- a/awx/main/tests/docs/test_swagger_generation.py +++ b/awx/main/tests/docs/test_swagger_generation.py @@ -91,7 +91,7 @@ class TestSwaggerGeneration(): # The number of API endpoints changes over time, but let's just check # for a reasonable number here; if this test starts failing, raise/lower the bounds paths = JSON['paths'] - assert 250 < len(paths) < 300 + assert 250 < len(paths) < 350 assert list(paths['/api/'].keys()) == ['get'] assert list(paths['/api/v2/'].keys()) == ['get'] assert list(sorted( diff --git a/awx/main/tests/functional/api/test_inventory.py b/awx/main/tests/functional/api/test_inventory.py index 78827dbe34..9340e8993b 100644 --- a/awx/main/tests/functional/api/test_inventory.py +++ b/awx/main/tests/functional/api/test_inventory.py @@ -42,10 +42,6 @@ def test_inventory_source_notification_on_cloud_only(get, post, inventory_source not_is = inventory_source_factory("not_ec2") - url = reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': cloud_is.id}) - response = post(url, dict(id=notification_template.id), u) - assert response.status_code == 204 - url = reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': not_is.id}) response = post(url, dict(id=notification_template.id), u) assert response.status_code == 400 diff --git a/awx/main/tests/functional/api/test_notifications.py b/awx/main/tests/functional/api/test_notifications.py new file mode 100644 index 0000000000..d211026b07 --- /dev/null +++ b/awx/main/tests/functional/api/test_notifications.py @@ -0,0 +1,129 @@ +import pytest + +from awx.api.versioning import reverse + + +@pytest.mark.django_db +def test_get_org_running_notification(get, admin, organization): + url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_org_running_notification(get, post, admin, notification_template, organization): + url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_get_project_running_notification(get, admin, project): + url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_project_running_notification(get, post, admin, notification_template, project): + url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_get_inv_src_running_notification(get, admin, inventory_source): + url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_inv_src_running_notification(get, post, admin, notification_template, inventory_source): + url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_get_jt_running_notification(get, admin, job_template): + url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_jt_running_notification(get, post, admin, notification_template, job_template): + url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_get_sys_jt_running_notification(get, admin, system_job_template): + url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_sys_jt_running_notification(get, post, admin, notification_template, system_job_template): + url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 + + +@pytest.mark.django_db +def test_get_wfjt_running_notification(get, admin, workflow_job_template): + url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk}) + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 0 + + +@pytest.mark.django_db +def test_post_wfjt_running_notification(get, post, admin, notification_template, workflow_job_template): + url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk}) + response = post(url, + dict(id=notification_template.id, + associate=True), + admin) + assert response.status_code == 204 + response = get(url, admin) + assert response.status_code == 200 + assert len(response.data['results']) == 1 diff --git a/awx/main/tests/functional/test_notifications.py b/awx/main/tests/functional/test_notifications.py index 5c2bf74d5a..576bc71a7a 100644 --- a/awx/main/tests/functional/test_notifications.py +++ b/awx/main/tests/functional/test_notifications.py @@ -92,27 +92,7 @@ def test_inherited_notification_templates(get, post, user, organization, project isrc.save() jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml') jt.save() - url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id}) - response = post(url, dict(id=notification_templates[0]), u) - assert response.status_code == 204 - url = reverse('api:project_notification_templates_any_list', kwargs={'pk': project.id}) - response = post(url, dict(id=notification_templates[1]), u) - assert response.status_code == 204 - url = reverse('api:job_template_notification_templates_any_list', kwargs={'pk': jt.id}) - response = post(url, dict(id=notification_templates[2]), u) - assert response.status_code == 204 - assert len(jt.notification_templates['any']) == 3 - assert len(project.notification_templates['any']) == 2 - assert len(isrc.notification_templates['any']) == 1 - - -@pytest.mark.django_db -def test_notification_template_merging(get, post, user, organization, project, notification_template): - user('admin-poster', True) - organization.notification_templates_any.add(notification_template) - project.notification_templates_any.add(notification_template) - assert len(project.notification_templates['any']) == 1 - + @pytest.mark.django_db def test_notification_template_simple_patch(patch, notification_template, admin): diff --git a/awx/main/tests/unit/api/serializers/test_inventory_serializers.py b/awx/main/tests/unit/api/serializers/test_inventory_serializers.py index 664f374483..a1191bea2c 100644 --- a/awx/main/tests/unit/api/serializers/test_inventory_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_inventory_serializers.py @@ -71,7 +71,7 @@ class TestInventorySourceSerializerGetRelated(object): 'activity_stream', 'notification_templates_error', 'notification_templates_success', - 'notification_templates_any', + 'notification_templates_started', 'inventory_updates', 'update', 'hosts', diff --git a/awx/main/tests/unit/api/serializers/test_job_template_serializers.py b/awx/main/tests/unit/api/serializers/test_job_template_serializers.py index 3e842a0598..698d27cb7c 100644 --- a/awx/main/tests/unit/api/serializers/test_job_template_serializers.py +++ b/awx/main/tests/unit/api/serializers/test_job_template_serializers.py @@ -50,7 +50,7 @@ class TestJobTemplateSerializerGetRelated(): 'schedules', 'activity_stream', 'launch', - 'notification_templates_any', + 'notification_templates_started', 'notification_templates_success', 'notification_templates_error', 'survey_spec', diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 2915a65aa1..0a84f754a5 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -378,6 +378,7 @@ class TestGenericRun(): job.status = 'running' job.cancel_flag = True job.websocket_emit_status = mock.Mock() + job.send_notification_templates = mock.Mock() task = tasks.RunJob() task.update_model = mock.Mock(wraps=update_model_wrapper) @@ -536,6 +537,7 @@ class TestAdhocRun(TestJobExecution): def test_options_jinja_usage(self, adhoc_job, adhoc_update_model_wrapper): adhoc_job.module_args = '{{ ansible_ssh_pass }}' adhoc_job.websocket_emit_status = mock.Mock() + adhoc_job.send_notification_templates = mock.Mock() task = tasks.RunAdHocCommand() task.update_model = mock.Mock(wraps=adhoc_update_model_wrapper) diff --git a/docs/notification_system.md b/docs/notification_system.md index 1415f30c96..7ef17d2cef 100644 --- a/docs/notification_system.md +++ b/docs/notification_system.md @@ -22,9 +22,9 @@ Notification templates assigned at certain levels will inherit notifications def ## Workflow -When a job succeeds or fails, the error or success handler will pull a list of relevant notifications using the procedure defined above. It will then create a Notification object for each one containing relevant details about the job and then **sends** it to the destination (email addresses, slack channel(s), SMS numbers, etc.). These Notification objects are available as related resources on job types (Jobs, Inventory Updates, Project Updates), and also at `/api/v2/notifications`. You may also see what notifications have been sent from a notifications by examining its related resources. +When a job starts, succeeds or fails, the running, success or error handler, respectively, will pull a list of relevant notifications using the procedure defined above. It then creates a Notification Object for each one containing relevant details about the job and then **sends** it to the destination (email addresses, Slack channel(s), SMS numbers, etc.). These Notification objects are available as related resources on job types (Jobs, Inventory Updates, Project Updates), and also at `/api/v2/notifications`. You may also see what notifications have been sent by examining its related resources. -Notifications can succeed or fail but that will not cause its associated job to succeed or fail. The status of the notification can be viewed at its detail endpoint: `/api/v2/notifications/` +Notifications can succeed or fail but that will _not_ cause its associated job to succeed or fail. The status of the notification can be viewed at its detail endpoint: `/api/v2/notifications/` ## Testing Notifications Before Using Them