mirror of
https://github.com/ansible/awx.git
synced 2026-04-28 05:05:25 -02:30
Merge branch 'notifications_work' into devel
* notifications_work: (23 commits) Updates to notification unit tests after @wwitzel3's feedback Fix some notifications issues and write some tests Add notification system documentation Clean up flake8 related issues Fixing up some unicode issues Implement tower ui view url on models Sanity check and force proper types in admin check Proper type for in check Adding migration and base notification type Add a periodic administrative notification Refactor message generator Support notification password field encryption Notification configuration type checking Refactor NotificationTemplate to Notifier Implement irc notification backend Add webhook notification backend Pagerduty and Hipchat backends plus some cleanup Notification serializers, views, and tasks Implement notification serializer and validations Notification endpoints and url expositions ...
This commit is contained in:
@@ -13,7 +13,7 @@ from rest_framework import serializers
|
||||
from rest_framework.request import clone_request
|
||||
|
||||
# Ansible Tower
|
||||
from awx.main.models import InventorySource
|
||||
from awx.main.models import InventorySource, Notifier
|
||||
|
||||
|
||||
class Metadata(metadata.SimpleMetadata):
|
||||
@@ -76,6 +76,12 @@ class Metadata(metadata.SimpleMetadata):
|
||||
get_group_by_choices = getattr(InventorySource, 'get_%s_group_by_choices' % cp)
|
||||
field_info['%s_group_by_choices' % cp] = get_group_by_choices()
|
||||
|
||||
# Special handling of notification configuration where the required properties
|
||||
# are conditional on the type selected.
|
||||
if field.field_name == 'notification_configuration':
|
||||
for (notification_type_name, notification_tr_name, notification_type_class) in Notifier.NOTIFICATION_TYPES:
|
||||
field_info[notification_type_name] = notification_type_class.init_parameters
|
||||
|
||||
# Update type of fields returned...
|
||||
if field.field_name == 'type':
|
||||
field_info['type'] = 'multiple choice'
|
||||
|
||||
@@ -481,6 +481,8 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
class EmptySerializer(serializers.Serializer):
|
||||
pass
|
||||
|
||||
class EmptySerializer(serializers.Serializer):
|
||||
pass
|
||||
|
||||
class BaseFactSerializer(DocumentSerializer):
|
||||
|
||||
@@ -794,7 +796,11 @@ class OrganizationSerializer(BaseSerializer):
|
||||
users = reverse('api:organization_users_list', args=(obj.pk,)),
|
||||
admins = reverse('api:organization_admins_list', args=(obj.pk,)),
|
||||
teams = reverse('api:organization_teams_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:organization_activity_stream_list', args=(obj.pk,))
|
||||
activity_stream = reverse('api:organization_activity_stream_list', args=(obj.pk,)),
|
||||
notifiers = reverse('api:organization_notifiers_list', args=(obj.pk,)),
|
||||
notifiers_any = reverse('api:organization_notifiers_any_list', args=(obj.pk,)),
|
||||
notifiers_success = reverse('api:organization_notifiers_success_list', args=(obj.pk,)),
|
||||
notifiers_error = reverse('api:organization_notifiers_error_list', args=(obj.pk,)),
|
||||
))
|
||||
return res
|
||||
|
||||
@@ -864,6 +870,9 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
||||
project_updates = reverse('api:project_updates_list', args=(obj.pk,)),
|
||||
schedules = reverse('api:project_schedules_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:project_activity_stream_list', args=(obj.pk,)),
|
||||
notifiers_any = reverse('api:project_notifiers_any_list', args=(obj.pk,)),
|
||||
notifiers_success = reverse('api:project_notifiers_success_list', args=(obj.pk,)),
|
||||
notifiers_error = reverse('api:project_notifiers_error_list', args=(obj.pk,)),
|
||||
))
|
||||
# Backwards compatibility.
|
||||
if obj.current_update:
|
||||
@@ -909,6 +918,7 @@ class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
|
||||
res.update(dict(
|
||||
project = reverse('api:project_detail', args=(obj.project.pk,)),
|
||||
cancel = reverse('api:project_update_cancel', args=(obj.pk,)),
|
||||
notifications = reverse('api:project_update_notifications_list', args=(obj.pk,)),
|
||||
))
|
||||
return res
|
||||
|
||||
@@ -1316,6 +1326,9 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
|
||||
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
|
||||
hosts = reverse('api:inventory_source_hosts_list', args=(obj.pk,)),
|
||||
groups = reverse('api:inventory_source_groups_list', args=(obj.pk,)),
|
||||
notifiers_any = reverse('api:inventory_source_notifiers_any_list', args=(obj.pk,)),
|
||||
notifiers_success = reverse('api:inventory_source_notifiers_success_list', args=(obj.pk,)),
|
||||
notifiers_error = reverse('api:inventory_source_notifiers_error_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
||||
@@ -1360,6 +1373,7 @@ class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSeri
|
||||
res.update(dict(
|
||||
inventory_source = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,)),
|
||||
cancel = reverse('api:inventory_update_cancel', args=(obj.pk,)),
|
||||
notifications = reverse('api:inventory_update_notifications_list', args=(obj.pk,)),
|
||||
))
|
||||
return res
|
||||
|
||||
@@ -1575,6 +1589,9 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
||||
schedules = reverse('api:job_template_schedules_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:job_template_activity_stream_list', args=(obj.pk,)),
|
||||
launch = reverse('api:job_template_launch', args=(obj.pk,)),
|
||||
notifiers_any = reverse('api:job_template_notifiers_any_list', args=(obj.pk,)),
|
||||
notifiers_success = reverse('api:job_template_notifiers_success_list', args=(obj.pk,)),
|
||||
notifiers_error = reverse('api:job_template_notifiers_error_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.host_config_key:
|
||||
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))
|
||||
@@ -1629,6 +1646,7 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
job_tasks = reverse('api:job_job_tasks_list', args=(obj.pk,)),
|
||||
job_host_summaries = reverse('api:job_job_host_summaries_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:job_activity_stream_list', args=(obj.pk,)),
|
||||
notifications = reverse('api:job_notifications_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.job_template and obj.job_template.active:
|
||||
res['job_template'] = reverse('api:job_template_detail',
|
||||
@@ -2044,6 +2062,79 @@ class JobLaunchSerializer(BaseSerializer):
|
||||
attrs = super(JobLaunchSerializer, self).validate(attrs)
|
||||
return attrs
|
||||
|
||||
class NotifierSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Notifier
|
||||
fields = ('*', 'organization', 'notification_type', 'notification_configuration')
|
||||
|
||||
type_map = {"string": (str, unicode),
|
||||
"int": (int,),
|
||||
"bool": (bool,),
|
||||
"list": (list,),
|
||||
"password": (str, unicode),
|
||||
"object": (dict,)}
|
||||
|
||||
def to_representation(self, obj):
|
||||
ret = super(NotifierSerializer, self).to_representation(obj)
|
||||
for field in obj.notification_class.init_parameters:
|
||||
if field in ret['notification_configuration'] and \
|
||||
force_text(ret['notification_configuration'][field]).startswith('$encrypted$'):
|
||||
ret['notification_configuration'][field] = '$encrypted$'
|
||||
return ret
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(NotifierSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
test = reverse('api:notifier_test', args=(obj.pk,)),
|
||||
notifications = reverse('api:notifier_notification_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.organization and obj.organization.active:
|
||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
||||
return res
|
||||
|
||||
def validate(self, attrs):
|
||||
notification_class = Notifier.CLASS_FOR_NOTIFICATION_TYPE[attrs['notification_type']]
|
||||
missing_fields = []
|
||||
incorrect_type_fields = []
|
||||
if 'notification_configuration' not in attrs:
|
||||
return attrs
|
||||
for field in notification_class.init_parameters:
|
||||
if field not in attrs['notification_configuration']:
|
||||
missing_fields.append(field)
|
||||
continue
|
||||
field_val = attrs['notification_configuration'][field]
|
||||
field_type = notification_class.init_parameters[field]['type']
|
||||
expected_types = self.type_map[field_type]
|
||||
if not type(field_val) in expected_types:
|
||||
incorrect_type_fields.append((field, field_type))
|
||||
continue
|
||||
if field_type == "password" and field_val.startswith('$encrypted$'):
|
||||
missing_fields.append(field)
|
||||
error_list = []
|
||||
if missing_fields:
|
||||
error_list.append("Missing required fields for Notification Configuration: {}".format(missing_fields))
|
||||
if incorrect_type_fields:
|
||||
for type_field_error in incorrect_type_fields:
|
||||
error_list.append("Configuration field '{}' incorrect type, expected {}".format(type_field_error[0],
|
||||
type_field_error[1]))
|
||||
if error_list:
|
||||
raise serializers.ValidationError(error_list)
|
||||
return attrs
|
||||
|
||||
class NotificationSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = ('*', '-name', '-description', 'notifier', 'error', 'status', 'notifications_sent',
|
||||
'notification_type', 'recipients', 'subject')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(NotificationSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
notifier = reverse('api:notifier_detail', args=(obj.notifier.pk,)),
|
||||
))
|
||||
return res
|
||||
|
||||
class ScheduleSerializer(BaseSerializer):
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ organization_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/projects/$', 'organization_projects_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/teams/$', 'organization_teams_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'organization_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers/$', 'organization_notifiers_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'organization_notifiers_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'organization_notifiers_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'organization_notifiers_success_list'),
|
||||
)
|
||||
|
||||
user_urls = patterns('awx.api.views',
|
||||
@@ -44,12 +48,16 @@ project_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/project_updates/$', 'project_updates_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'project_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', 'project_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'project_notifiers_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'project_notifiers_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'project_notifiers_success_list'),
|
||||
)
|
||||
|
||||
project_update_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'project_update_detail'),
|
||||
url(r'^(?P<pk>[0-9]+)/cancel/$', 'project_update_cancel'),
|
||||
url(r'^(?P<pk>[0-9]+)/stdout/$', 'project_update_stdout'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifications/$', 'project_update_notifications_list'),
|
||||
)
|
||||
|
||||
team_urls = patterns('awx.api.views',
|
||||
@@ -121,12 +129,16 @@ inventory_source_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', 'inventory_source_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/groups/$', 'inventory_source_groups_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/hosts/$', 'inventory_source_hosts_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'inventory_source_notifiers_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'inventory_source_notifiers_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'inventory_source_notifiers_success_list'),
|
||||
)
|
||||
|
||||
inventory_update_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'inventory_update_detail'),
|
||||
url(r'^(?P<pk>[0-9]+)/cancel/$', 'inventory_update_cancel'),
|
||||
url(r'^(?P<pk>[0-9]+)/stdout/$', 'inventory_update_stdout'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifications/$', 'inventory_update_notifications_list'),
|
||||
)
|
||||
|
||||
inventory_script_urls = patterns('awx.api.views',
|
||||
@@ -154,6 +166,9 @@ job_template_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/schedules/$', 'job_template_schedules_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/survey_spec/$', 'job_template_survey_spec'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'job_template_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'job_template_notifiers_any_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'job_template_notifiers_error_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'job_template_notifiers_success_list'),
|
||||
)
|
||||
|
||||
job_urls = patterns('awx.api.views',
|
||||
@@ -168,6 +183,7 @@ job_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/job_tasks/$', 'job_job_tasks_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'job_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/stdout/$', 'job_stdout'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifications/$', 'job_notifications_list'),
|
||||
)
|
||||
|
||||
job_host_summary_urls = patterns('awx.api.views',
|
||||
@@ -210,6 +226,18 @@ system_job_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/cancel/$', 'system_job_cancel'),
|
||||
)
|
||||
|
||||
notifier_urls = patterns('awx.api.views',
|
||||
url(r'^$', 'notifier_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'notifier_detail'),
|
||||
url(r'^(?P<pk>[0-9]+)/test/$', 'notifier_test'),
|
||||
url(r'^(?P<pk>[0-9]+)/notifications/$', 'notifier_notification_list'),
|
||||
)
|
||||
|
||||
notification_urls = patterns('awx.api.views',
|
||||
url(r'^$', 'notification_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'notification_detail'),
|
||||
)
|
||||
|
||||
schedule_urls = patterns('awx.api.views',
|
||||
url(r'^$', 'schedule_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'schedule_detail'),
|
||||
@@ -258,6 +286,8 @@ v1_urls = patterns('awx.api.views',
|
||||
url(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
|
||||
url(r'^system_job_templates/', include(system_job_template_urls)),
|
||||
url(r'^system_jobs/', include(system_job_urls)),
|
||||
url(r'^notifiers/', include(notifier_urls)),
|
||||
url(r'^notifications/', include(notification_urls)),
|
||||
url(r'^unified_job_templates/$', 'unified_job_template_list'),
|
||||
url(r'^unified_jobs/$', 'unified_job_list'),
|
||||
url(r'^activity_stream/', include(activity_stream_urls)),
|
||||
|
||||
168
awx/api/views.py
168
awx/api/views.py
@@ -56,7 +56,7 @@ from social.backends.utils import load_backends
|
||||
|
||||
# AWX
|
||||
from awx.main.task_engine import TaskSerializer, TASK_FILE, TEMPORARY_TASK_FILE
|
||||
from awx.main.tasks import mongodb_control
|
||||
from awx.main.tasks import mongodb_control, send_notifications
|
||||
from awx.main.access import get_user_queryset
|
||||
from awx.main.ha import is_ha_environment
|
||||
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
|
||||
@@ -135,6 +135,8 @@ class ApiV1RootView(APIView):
|
||||
data['system_job_templates'] = reverse('api:system_job_template_list')
|
||||
data['system_jobs'] = reverse('api:system_job_list')
|
||||
data['schedules'] = reverse('api:schedule_list')
|
||||
data['notifiers'] = reverse('api:notifier_list')
|
||||
data['notifications'] = reverse('api:notification_list')
|
||||
data['unified_job_templates'] = reverse('api:unified_job_template_list')
|
||||
data['unified_jobs'] = reverse('api:unified_job_list')
|
||||
data['activity_stream'] = reverse('api:activity_stream_list')
|
||||
@@ -266,6 +268,7 @@ class ApiV1ConfigView(APIView):
|
||||
# If the license is valid, write it to disk.
|
||||
if license_data['valid_key']:
|
||||
tower_settings.LICENSE = data_actual
|
||||
tower_settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
|
||||
|
||||
# Spawn a task to ensure that MongoDB is started (or stopped)
|
||||
# as appropriate, based on whether the license uses it.
|
||||
@@ -696,6 +699,35 @@ class OrganizationActivityStreamList(SubListAPIView):
|
||||
# Okay, let it through.
|
||||
return super(type(self), self).get(request, *args, **kwargs)
|
||||
|
||||
class OrganizationNotifiersList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notifiers'
|
||||
parent_key = 'organization'
|
||||
|
||||
class OrganizationNotifiersAnyList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notifiers_any'
|
||||
|
||||
class OrganizationNotifiersErrorList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notifiers_error'
|
||||
|
||||
class OrganizationNotifiersSuccessList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'notifiers_success'
|
||||
|
||||
class TeamList(ListCreateAPIView):
|
||||
|
||||
model = Team
|
||||
@@ -861,6 +893,26 @@ class ProjectActivityStreamList(SubListAPIView):
|
||||
return qs.filter(project=parent)
|
||||
return qs.filter(Q(project=parent) | Q(credential__in=parent.credential))
|
||||
|
||||
class ProjectNotifiersAnyList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Project
|
||||
relationship = 'notifiers_any'
|
||||
|
||||
class ProjectNotifiersErrorList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Project
|
||||
relationship = 'notifiers_error'
|
||||
|
||||
class ProjectNotifiersSuccessList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = Project
|
||||
relationship = 'notifiers_success'
|
||||
|
||||
class ProjectUpdatesList(SubListAPIView):
|
||||
|
||||
@@ -911,6 +963,12 @@ class ProjectUpdateCancel(RetrieveAPIView):
|
||||
else:
|
||||
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||
|
||||
class ProjectUpdateNotificationsList(SubListAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
parent_model = Project
|
||||
relationship = 'notifications'
|
||||
|
||||
class UserList(ListCreateAPIView):
|
||||
|
||||
@@ -1783,6 +1841,27 @@ class InventorySourceActivityStreamList(SubListAPIView):
|
||||
# Okay, let it through.
|
||||
return super(type(self), self).get(request, *args, **kwargs)
|
||||
|
||||
class InventorySourceNotifiersAnyList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = InventorySource
|
||||
relationship = 'notifiers_any'
|
||||
|
||||
class InventorySourceNotifiersErrorList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = InventorySource
|
||||
relationship = 'notifiers_error'
|
||||
|
||||
class InventorySourceNotifiersSuccessList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = InventorySource
|
||||
relationship = 'notifiers_success'
|
||||
|
||||
class InventorySourceHostsList(SubListAPIView):
|
||||
|
||||
model = Host
|
||||
@@ -1847,6 +1926,13 @@ class InventoryUpdateCancel(RetrieveAPIView):
|
||||
else:
|
||||
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||
|
||||
class InventoryUpdateNotificationsList(SubListAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
parent_model = InventoryUpdate
|
||||
relationship = 'notifications'
|
||||
|
||||
class JobTemplateList(ListCreateAPIView):
|
||||
|
||||
model = JobTemplate
|
||||
@@ -2016,6 +2102,27 @@ class JobTemplateActivityStreamList(SubListAPIView):
|
||||
# Okay, let it through.
|
||||
return super(type(self), self).get(request, *args, **kwargs)
|
||||
|
||||
class JobTemplateNotifiersAnyList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = JobTemplate
|
||||
relationship = 'notifiers_any'
|
||||
|
||||
class JobTemplateNotifiersErrorList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = JobTemplate
|
||||
relationship = 'notifiers_error'
|
||||
|
||||
class JobTemplateNotifiersSuccessList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
parent_model = JobTemplate
|
||||
relationship = 'notifiers_success'
|
||||
|
||||
class JobTemplateCallback(GenericAPIView):
|
||||
|
||||
model = JobTemplate
|
||||
@@ -2349,6 +2456,13 @@ class JobRelaunch(RetrieveAPIView, GenericAPIView):
|
||||
headers = {'Location': new_job.get_absolute_url()}
|
||||
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
class JobNotificationsList(SubListAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
parent_model = Job
|
||||
relationship = 'notifications'
|
||||
|
||||
class BaseJobHostSummariesList(SubListAPIView):
|
||||
|
||||
model = JobHostSummary
|
||||
@@ -3002,6 +3116,58 @@ class AdHocCommandStdout(UnifiedJobStdout):
|
||||
model = AdHocCommand
|
||||
new_in_220 = True
|
||||
|
||||
class NotifierList(ListCreateAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
new_in_300 = True
|
||||
|
||||
class NotifierDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
model = Notifier
|
||||
serializer_class = NotifierSerializer
|
||||
new_in_300 = True
|
||||
|
||||
class NotifierTest(GenericAPIView):
|
||||
|
||||
view_name = 'Notifier Test'
|
||||
model = Notifier
|
||||
serializer_class = EmptySerializer
|
||||
new_in_300 = True
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
notification = obj.generate_notification("Tower Notification Test {} {}".format(obj.id, tower_settings.TOWER_URL_BASE),
|
||||
{"body": "Ansible Tower Test Notification {} {}".format(obj.id, tower_settings.TOWER_URL_BASE)})
|
||||
if not notification:
|
||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
send_notifications.delay([notification.id])
|
||||
headers = {'Location': notification.get_absolute_url()}
|
||||
return Response({"notification": notification.id},
|
||||
headers=headers,
|
||||
status=status.HTTP_202_ACCEPTED)
|
||||
|
||||
class NotifierNotificationList(SubListAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
parent_model = Notifier
|
||||
relationship = 'notifications'
|
||||
parent_key = 'notifier'
|
||||
|
||||
class NotificationList(ListAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
new_in_300 = True
|
||||
|
||||
class NotificationDetail(RetrieveAPIView):
|
||||
|
||||
model = Notification
|
||||
serializer_class = NotificationSerializer
|
||||
new_in_300 = True
|
||||
|
||||
class ActivityStreamList(SimpleListAPIView):
|
||||
|
||||
model = ActivityStream
|
||||
|
||||
Reference in New Issue
Block a user