add API versioning for /api/v2/

This commit is contained in:
Ryan Petrello
2017-03-29 16:48:10 -04:00
parent 7dda6106d1
commit 95ea370e5e
52 changed files with 756 additions and 700 deletions

View File

@@ -31,6 +31,7 @@ from awx.api.filters import FieldLookupBackend
from awx.main.models import * # noqa
from awx.main.utils import * # noqa
from awx.api.serializers import ResourceAccessListElementSerializer
from awx.api.versioning import URLPathVersioning
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
@@ -86,6 +87,8 @@ def get_view_description(cls, html=False):
class APIView(views.APIView):
versioning_class = URLPathVersioning
def initialize_request(self, request, *args, **kwargs):
'''
Store the Django REST Framework Request object as an attribute on the
@@ -161,6 +164,7 @@ class APIView(views.APIView):
'new_in_240': getattr(self, 'new_in_240', False),
'new_in_300': getattr(self, 'new_in_300', False),
'new_in_310': getattr(self, 'new_in_310', False),
'new_in_320': getattr(self, 'new_in_320', False),
'deprecated': getattr(self, 'deprecated', False),
}
@@ -188,6 +192,23 @@ class APIView(views.APIView):
return data
def determine_version(self, request, *args, **kwargs):
return (
getattr(request, 'version', None),
getattr(request, 'versioning_scheme', None),
)
def dispatch(self, request, *args, **kwargs):
if self.versioning_class is not None:
scheme = self.versioning_class()
request.version, request.versioning_scheme = (
scheme.determine_version(request, *args, **kwargs),
scheme
)
if 'version' in kwargs:
kwargs.pop('version')
return super(APIView, self).dispatch(request, *args, **kwargs)
class GenericAPIView(generics.GenericAPIView, APIView):
# Base class for all model-based views.
@@ -424,7 +445,7 @@ class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
obj = serializer.save()
serializer = self.get_serializer(instance=obj)
headers = {'Location': obj.get_absolute_url()}
headers = {'Location': obj.get_absolute_url(request)}
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

View File

@@ -4,9 +4,10 @@
# Python
import copy
import json
import logging
import re
import six
import logging
import urllib
from collections import OrderedDict
from dateutil import rrule
@@ -18,7 +19,6 @@ from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
@@ -43,11 +43,12 @@ from awx.main.models import * # noqa
from awx.main.access import get_user_capabilities
from awx.main.fields import ImplicitRoleField
from awx.main.utils import (
get_type_for_model, get_model_for_type, build_url, timestamp_apiformat,
get_type_for_model, get_model_for_type, timestamp_apiformat,
camelcase_to_underscore, getattrd, parse_yaml_or_json)
from awx.main.validators import vars_validate_or_raise
from awx.conf.license import feature_enabled
from awx.api.versioning import reverse
from awx.api.fields import BooleanNullField, CharNullField, ChoiceNullField, EncryptedPasswordField, VerbatimField
logger = logging.getLogger('awx.api.serializers')
@@ -103,7 +104,7 @@ SUMMARIZABLE_FK_FIELDS = {
}
def reverse_gfk(content_object):
def reverse_gfk(content_object, request):
'''
Computes a reverse for a GenericForeignKey field.
@@ -116,7 +117,7 @@ def reverse_gfk(content_object):
return {}
return {
camelcase_to_underscore(content_object.__class__.__name__): content_object.get_absolute_url()
camelcase_to_underscore(content_object.__class__.__name__): content_object.get_absolute_url(request=request)
}
@@ -268,9 +269,9 @@ class BaseSerializer(serializers.ModelSerializer):
if obj is None or not hasattr(obj, 'get_absolute_url'):
return ''
elif isinstance(obj, User):
return reverse('api:user_detail', args=(obj.pk,))
return self.reverse('api:user_detail', kwargs={'pk': obj.pk})
else:
return obj.get_absolute_url()
return obj.get_absolute_url(request=self.context.get('request'))
def _get_related(self, obj):
return {} if obj is None else self.get_related(obj)
@@ -278,9 +279,9 @@ class BaseSerializer(serializers.ModelSerializer):
def get_related(self, obj):
res = OrderedDict()
if getattr(obj, 'created_by', None):
res['created_by'] = reverse('api:user_detail', args=(obj.created_by.pk,))
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
if getattr(obj, 'modified_by', None):
res['modified_by'] = reverse('api:user_detail', args=(obj.modified_by.pk,))
res['modified_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.modified_by.pk})
return res
def _get_summary_fields(self, obj):
@@ -496,6 +497,10 @@ class BaseSerializer(serializers.ModelSerializer):
raise ValidationError(d)
return attrs
def reverse(self, *args, **kwargs):
kwargs['request'] = self.context.get('request')
return reverse(*args, **kwargs)
class EmptySerializer(serializers.Serializer):
pass
@@ -525,11 +530,11 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
def get_related(self, obj):
res = super(UnifiedJobTemplateSerializer, self).get_related(obj)
if obj.current_job:
res['current_job'] = obj.current_job.get_absolute_url()
res['current_job'] = obj.current_job.get_absolute_url(request=self.context.get('request'))
if obj.last_job:
res['last_job'] = obj.last_job.get_absolute_url()
res['last_job'] = obj.last_job.get_absolute_url(request=self.context.get('request'))
if obj.next_schedule:
res['next_schedule'] = obj.next_schedule.get_absolute_url()
res['next_schedule'] = obj.next_schedule.get_absolute_url(request=self.context.get('request'))
return res
def get_types(self):
@@ -589,19 +594,19 @@ class UnifiedJobSerializer(BaseSerializer):
def get_related(self, obj):
res = super(UnifiedJobSerializer, self).get_related(obj)
if obj.unified_job_template:
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(request=self.context.get('request'))
if obj.schedule:
res['schedule'] = obj.schedule.get_absolute_url()
res['schedule'] = obj.schedule.get_absolute_url(request=self.context.get('request'))
if isinstance(obj, ProjectUpdate):
res['stdout'] = reverse('api:project_update_stdout', args=(obj.pk,))
res['stdout'] = self.reverse('api:project_update_stdout', kwargs={'pk': obj.pk})
elif isinstance(obj, InventoryUpdate):
res['stdout'] = reverse('api:inventory_update_stdout', args=(obj.pk,))
res['stdout'] = self.reverse('api:inventory_update_stdout', kwargs={'pk': obj.pk})
elif isinstance(obj, Job):
res['stdout'] = reverse('api:job_stdout', args=(obj.pk,))
res['stdout'] = self.reverse('api:job_stdout', kwargs={'pk': obj.pk})
elif isinstance(obj, AdHocCommand):
res['stdout'] = reverse('api:ad_hoc_command_stdout', args=(obj.pk,))
res['stdout'] = self.reverse('api:ad_hoc_command_stdout', kwargs={'pk': obj.pk})
if obj.workflow_job_id:
res['source_workflow_job'] = reverse('api:workflow_job_detail', args=(obj.workflow_job_id,))
res['source_workflow_job'] = self.reverse('api:workflow_job_detail', kwargs={'pk': obj.workflow_job_id})
return res
def get_summary_fields(self, obj):
@@ -811,14 +816,14 @@ class UserSerializer(BaseSerializer):
def get_related(self, obj):
res = super(UserSerializer, self).get_related(obj)
res.update(dict(
teams = reverse('api:user_teams_list', args=(obj.pk,)),
organizations = reverse('api:user_organizations_list', args=(obj.pk,)),
admin_of_organizations = reverse('api:user_admin_of_organizations_list', args=(obj.pk,)),
projects = reverse('api:user_projects_list', args=(obj.pk,)),
credentials = reverse('api:user_credentials_list', args=(obj.pk,)),
roles = reverse('api:user_roles_list', args=(obj.pk,)),
activity_stream = reverse('api:user_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:user_access_list', args=(obj.pk,)),
teams = self.reverse('api:user_teams_list', kwargs={'pk': obj.pk}),
organizations = self.reverse('api:user_organizations_list', kwargs={'pk': obj.pk}),
admin_of_organizations = self.reverse('api:user_admin_of_organizations_list', kwargs={'pk': obj.pk}),
projects = self.reverse('api:user_projects_list', kwargs={'pk': obj.pk}),
credentials = self.reverse('api:user_credentials_list', kwargs={'pk': obj.pk}),
roles = self.reverse('api:user_roles_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:user_activity_stream_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:user_access_list', kwargs={'pk': obj.pk}),
))
return res
@@ -864,20 +869,20 @@ class OrganizationSerializer(BaseSerializer):
def get_related(self, obj):
res = super(OrganizationSerializer, self).get_related(obj)
res.update(dict(
projects = reverse('api:organization_projects_list', args=(obj.pk,)),
inventories = reverse('api:organization_inventories_list', args=(obj.pk,)),
workflow_job_templates = reverse('api:organization_workflow_job_templates_list', args=(obj.pk,)),
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,)),
credentials = reverse('api:organization_credential_list', args=(obj.pk,)),
activity_stream = reverse('api:organization_activity_stream_list', args=(obj.pk,)),
notification_templates = reverse('api:organization_notification_templates_list', args=(obj.pk,)),
notification_templates_any = reverse('api:organization_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:organization_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:organization_notification_templates_error_list', args=(obj.pk,)),
object_roles = reverse('api:organization_object_roles_list', args=(obj.pk,)),
access_list = reverse('api:organization_access_list', args=(obj.pk,)),
projects = self.reverse('api:organization_projects_list', kwargs={'pk': obj.pk}),
inventories = self.reverse('api:organization_inventories_list', kwargs={'pk': obj.pk}),
workflow_job_templates = self.reverse('api:organization_workflow_job_templates_list', kwargs={'pk': obj.pk}),
users = self.reverse('api:organization_users_list', kwargs={'pk': obj.pk}),
admins = self.reverse('api:organization_admins_list', kwargs={'pk': obj.pk}),
teams = self.reverse('api:organization_teams_list', kwargs={'pk': obj.pk}),
credentials = self.reverse('api:organization_credential_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_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}),
access_list = self.reverse('api:organization_access_list', kwargs={'pk': obj.pk}),
))
return res
@@ -903,8 +908,8 @@ class ProjectOptionsSerializer(BaseSerializer):
def get_related(self, obj):
res = super(ProjectOptionsSerializer, self).get_related(obj)
if obj.credential:
res['credential'] = reverse('api:credential_detail',
args=(obj.credential.pk,))
res['credential'] = self.reverse('api:credential_detail',
kwargs={'pk': obj.credential.pk})
return res
def validate(self, attrs):
@@ -953,28 +958,28 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
def get_related(self, obj):
res = super(ProjectSerializer, self).get_related(obj)
res.update(dict(
teams = reverse('api:project_teams_list', args=(obj.pk,)),
playbooks = reverse('api:project_playbooks', args=(obj.pk,)),
update = reverse('api:project_update_view', args=(obj.pk,)),
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,)),
notification_templates_any = reverse('api:project_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:project_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:project_notification_templates_error_list', args=(obj.pk,)),
access_list = reverse('api:project_access_list', args=(obj.pk,)),
object_roles = reverse('api:project_object_roles_list', args=(obj.pk,)),
teams = self.reverse('api:project_teams_list', kwargs={'pk': obj.pk}),
playbooks = self.reverse('api:project_playbooks', kwargs={'pk': obj.pk}),
update = self.reverse('api:project_update_view', kwargs={'pk': obj.pk}),
project_updates = self.reverse('api:project_updates_list', 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_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}),
object_roles = self.reverse('api:project_object_roles_list', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail',
args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail',
kwargs={'pk': obj.organization.pk})
# Backwards compatibility.
if obj.current_update:
res['current_update'] = reverse('api:project_update_detail',
args=(obj.current_update.pk,))
res['current_update'] = self.reverse('api:project_update_detail',
kwargs={'pk': obj.current_update.pk})
if obj.last_update:
res['last_update'] = reverse('api:project_update_detail',
args=(obj.last_update.pk,))
res['last_update'] = self.reverse('api:project_update_detail',
kwargs={'pk': obj.last_update.pk})
return res
def to_representation(self, obj):
@@ -1039,9 +1044,9 @@ class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
def get_related(self, obj):
res = super(ProjectUpdateSerializer, self).get_related(obj)
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,)),
project = self.reverse('api:project_detail', kwargs={'pk': obj.project.pk}),
cancel = self.reverse('api:project_update_cancel', kwargs={'pk': obj.pk}),
notifications = self.reverse('api:project_update_notifications_list', kwargs={'pk': obj.pk}),
))
return res
@@ -1078,23 +1083,22 @@ class InventorySerializer(BaseSerializerWithVariables):
def get_related(self, obj):
res = super(InventorySerializer, self).get_related(obj)
res.update(dict(
hosts = reverse('api:inventory_hosts_list', args=(obj.pk,)),
groups = reverse('api:inventory_groups_list', args=(obj.pk,)),
root_groups = reverse('api:inventory_root_groups_list', args=(obj.pk,)),
variable_data = reverse('api:inventory_variable_data', args=(obj.pk,)),
script = reverse('api:inventory_script_view', args=(obj.pk,)),
tree = reverse('api:inventory_tree_view', args=(obj.pk,)),
inventory_sources = reverse('api:inventory_inventory_sources_list', args=(obj.pk,)),
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
job_templates = reverse('api:inventory_job_template_list', args=(obj.pk,)),
scan_job_templates = reverse('api:inventory_scan_job_template_list', args=(obj.pk,)),
ad_hoc_commands = reverse('api:inventory_ad_hoc_commands_list', args=(obj.pk,)),
access_list = reverse('api:inventory_access_list', args=(obj.pk,)),
object_roles = reverse('api:inventory_object_roles_list', args=(obj.pk,)),
#single_fact = reverse('api:inventory_single_fact_view', args=(obj.pk,)),
hosts = self.reverse('api:inventory_hosts_list', kwargs={'pk': obj.pk}),
groups = self.reverse('api:inventory_groups_list', kwargs={'pk': obj.pk}),
root_groups = self.reverse('api:inventory_root_groups_list', kwargs={'pk': obj.pk}),
variable_data = self.reverse('api:inventory_variable_data', kwargs={'pk': obj.pk}),
script = self.reverse('api:inventory_script_view', kwargs={'pk': obj.pk}),
tree = self.reverse('api:inventory_tree_view', kwargs={'pk': obj.pk}),
inventory_sources = self.reverse('api:inventory_inventory_sources_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:inventory_activity_stream_list', kwargs={'pk': obj.pk}),
job_templates = self.reverse('api:inventory_job_template_list', kwargs={'pk': obj.pk}),
scan_job_templates = self.reverse('api:inventory_scan_job_template_list', kwargs={'pk': obj.pk}),
ad_hoc_commands = self.reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:inventory_access_list', kwargs={'pk': obj.pk}),
object_roles = self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
def to_representation(self, obj):
@@ -1143,24 +1147,23 @@ class HostSerializer(BaseSerializerWithVariables):
def get_related(self, obj):
res = super(HostSerializer, self).get_related(obj)
res.update(dict(
variable_data = reverse('api:host_variable_data', args=(obj.pk,)),
groups = reverse('api:host_groups_list', args=(obj.pk,)),
all_groups = reverse('api:host_all_groups_list', args=(obj.pk,)),
job_events = reverse('api:host_job_events_list', args=(obj.pk,)),
job_host_summaries = reverse('api:host_job_host_summaries_list', args=(obj.pk,)),
activity_stream = reverse('api:host_activity_stream_list', args=(obj.pk,)),
inventory_sources = reverse('api:host_inventory_sources_list', args=(obj.pk,)),
ad_hoc_commands = reverse('api:host_ad_hoc_commands_list', args=(obj.pk,)),
ad_hoc_command_events = reverse('api:host_ad_hoc_command_events_list', args=(obj.pk,)),
fact_versions = reverse('api:host_fact_versions_list', args=(obj.pk,)),
#single_fact = reverse('api:host_single_fact_view', args=(obj.pk,)),
variable_data = self.reverse('api:host_variable_data', kwargs={'pk': obj.pk}),
groups = self.reverse('api:host_groups_list', kwargs={'pk': obj.pk}),
all_groups = self.reverse('api:host_all_groups_list', kwargs={'pk': obj.pk}),
job_events = self.reverse('api:host_job_events_list', kwargs={'pk': obj.pk}),
job_host_summaries = self.reverse('api:host_job_host_summaries_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:host_activity_stream_list', kwargs={'pk': obj.pk}),
inventory_sources = self.reverse('api:host_inventory_sources_list', kwargs={'pk': obj.pk}),
ad_hoc_commands = self.reverse('api:host_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
ad_hoc_command_events = self.reverse('api:host_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
fact_versions = self.reverse('api:host_fact_versions_list', kwargs={'pk': obj.pk}),
))
if obj.inventory:
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.last_job:
res['last_job'] = reverse('api:job_detail', args=(obj.last_job.pk,))
res['last_job'] = self.reverse('api:job_detail', kwargs={'pk': obj.last_job.pk})
if obj.last_job_host_summary:
res['last_job_host_summary'] = reverse('api:job_host_summary_detail', args=(obj.last_job_host_summary.pk,))
res['last_job_host_summary'] = self.reverse('api:job_host_summary_detail', kwargs={'pk': obj.last_job_host_summary.pk})
return res
def get_summary_fields(self, obj):
@@ -1253,22 +1256,21 @@ class GroupSerializer(BaseSerializerWithVariables):
def get_related(self, obj):
res = super(GroupSerializer, self).get_related(obj)
res.update(dict(
variable_data = reverse('api:group_variable_data', args=(obj.pk,)),
hosts = reverse('api:group_hosts_list', args=(obj.pk,)),
potential_children = reverse('api:group_potential_children_list', args=(obj.pk,)),
children = reverse('api:group_children_list', args=(obj.pk,)),
all_hosts = reverse('api:group_all_hosts_list', args=(obj.pk,)),
job_events = reverse('api:group_job_events_list', args=(obj.pk,)),
job_host_summaries = reverse('api:group_job_host_summaries_list', args=(obj.pk,)),
activity_stream = reverse('api:group_activity_stream_list', args=(obj.pk,)),
inventory_sources = reverse('api:group_inventory_sources_list', args=(obj.pk,)),
ad_hoc_commands = reverse('api:group_ad_hoc_commands_list', args=(obj.pk,)),
#single_fact = reverse('api:group_single_fact_view', args=(obj.pk,)),
variable_data = self.reverse('api:group_variable_data', kwargs={'pk': obj.pk}),
hosts = self.reverse('api:group_hosts_list', kwargs={'pk': obj.pk}),
potential_children = self.reverse('api:group_potential_children_list', kwargs={'pk': obj.pk}),
children = self.reverse('api:group_children_list', kwargs={'pk': obj.pk}),
all_hosts = self.reverse('api:group_all_hosts_list', kwargs={'pk': obj.pk}),
job_events = self.reverse('api:group_job_events_list', kwargs={'pk': obj.pk}),
job_host_summaries = self.reverse('api:group_job_host_summaries_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:group_activity_stream_list', kwargs={'pk': obj.pk}),
inventory_sources = self.reverse('api:group_inventory_sources_list', kwargs={'pk': obj.pk}),
ad_hoc_commands = self.reverse('api:group_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
))
if obj.inventory:
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.inventory_source:
res['inventory_source'] = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,))
res['inventory_source'] = self.reverse('api:inventory_source_detail', kwargs={'pk': obj.inventory_source.pk})
return res
def validate_name(self, value):
@@ -1363,11 +1365,11 @@ class CustomInventoryScriptSerializer(BaseSerializer):
def get_related(self, obj):
res = super(CustomInventoryScriptSerializer, self).get_related(obj)
res.update(dict(
object_roles = reverse('api:inventory_script_object_roles_list', args=(obj.pk,)),
object_roles = self.reverse('api:inventory_script_object_roles_list', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
@@ -1381,10 +1383,10 @@ class InventorySourceOptionsSerializer(BaseSerializer):
def get_related(self, obj):
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
if obj.credential:
res['credential'] = reverse('api:credential_detail',
args=(obj.credential.pk,))
res['credential'] = self.reverse('api:credential_detail',
kwargs={'pk': obj.credential.pk})
if obj.source_script:
res['source_script'] = reverse('api:inventory_script_detail', args=(obj.source_script.pk,))
res['source_script'] = self.reverse('api:inventory_script_detail', kwargs={'pk': obj.source_script.pk})
return res
def validate_source_vars(self, value):
@@ -1437,27 +1439,27 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
def get_related(self, obj):
res = super(InventorySourceSerializer, self).get_related(obj)
res.update(dict(
update = reverse('api:inventory_source_update_view', args=(obj.pk,)),
inventory_updates = reverse('api:inventory_source_updates_list', args=(obj.pk,)),
schedules = reverse('api:inventory_source_schedules_list', args=(obj.pk,)),
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,)),
notification_templates_any = reverse('api:inventory_source_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:inventory_source_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:inventory_source_notification_templates_error_list', args=(obj.pk,)),
update = self.reverse('api:inventory_source_update_view', kwargs={'pk': obj.pk}),
inventory_updates = self.reverse('api:inventory_source_updates_list', kwargs={'pk': obj.pk}),
schedules = self.reverse('api:inventory_source_schedules_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:inventory_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_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}),
))
if obj.inventory:
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.group:
res['group'] = reverse('api:group_detail', args=(obj.group.pk,))
res['group'] = self.reverse('api:group_detail', kwargs={'pk': obj.group.pk})
# Backwards compatibility.
if obj.current_update:
res['current_update'] = reverse('api:inventory_update_detail',
args=(obj.current_update.pk,))
res['current_update'] = self.reverse('api:inventory_update_detail',
kwargs={'pk': obj.current_update.pk})
if obj.last_update:
res['last_update'] = reverse('api:inventory_update_detail',
args=(obj.last_update.pk,))
res['last_update'] = self.reverse('api:inventory_update_detail',
kwargs={'pk': obj.last_update.pk})
return res
def to_representation(self, obj):
@@ -1488,9 +1490,9 @@ class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSeri
def get_related(self, obj):
res = super(InventoryUpdateSerializer, self).get_related(obj)
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,)),
inventory_source = self.reverse('api:inventory_source_detail', kwargs={'pk': obj.inventory_source.pk}),
cancel = self.reverse('api:inventory_update_cancel', kwargs={'pk': obj.pk}),
notifications = self.reverse('api:inventory_update_notifications_list', kwargs={'pk': obj.pk}),
))
return res
@@ -1518,16 +1520,16 @@ class TeamSerializer(BaseSerializer):
def get_related(self, obj):
res = super(TeamSerializer, self).get_related(obj)
res.update(dict(
projects = reverse('api:team_projects_list', args=(obj.pk,)),
users = reverse('api:team_users_list', args=(obj.pk,)),
credentials = reverse('api:team_credentials_list', args=(obj.pk,)),
roles = reverse('api:team_roles_list', args=(obj.pk,)),
object_roles = reverse('api:team_object_roles_list', args=(obj.pk,)),
activity_stream = reverse('api:team_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:team_access_list', args=(obj.pk,)),
projects = self.reverse('api:team_projects_list', kwargs={'pk': obj.pk}),
users = self.reverse('api:team_users_list', kwargs={'pk': obj.pk}),
credentials = self.reverse('api:team_credentials_list', kwargs={'pk': obj.pk}),
roles = self.reverse('api:team_roles_list', kwargs={'pk': obj.pk}),
object_roles = self.reverse('api:team_object_roles_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:team_activity_stream_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:team_access_list', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
def to_representation(self, obj):
@@ -1564,11 +1566,11 @@ class RoleSerializer(BaseSerializer):
def get_related(self, obj):
ret = super(RoleSerializer, self).get_related(obj)
ret['users'] = reverse('api:role_users_list', args=(obj.pk,))
ret['teams'] = reverse('api:role_teams_list', args=(obj.pk,))
ret['users'] = self.reverse('api:role_users_list', kwargs={'pk': obj.pk})
ret['teams'] = self.reverse('api:role_teams_list', kwargs={'pk': obj.pk})
try:
if obj.content_object:
ret.update(reverse_gfk(obj.content_object))
ret.update(reverse_gfk(obj.content_object, self.context.get('request')))
except AttributeError:
# AttributeError's happen if our content_object is pointing at
# a model that no longer exists. This is dirty data and ideally
@@ -1610,7 +1612,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
try:
role_dict['resource_name'] = role.content_object.name
role_dict['resource_type'] = role.content_type.name
role_dict['related'] = reverse_gfk(role.content_object)
role_dict['related'] = reverse_gfk(role.content_object, self.context.get('request'))
except AttributeError:
pass
if role.content_type is not None:
@@ -1638,7 +1640,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
if role.content_type is not None:
role_dict['resource_name'] = role.content_object.name
role_dict['resource_type'] = role.content_type.name
role_dict['related'] = reverse_gfk(role.content_object)
role_dict['related'] = reverse_gfk(role.content_object, self.context.get('request'))
role_dict['user_capabilities'] = {'unattach': requesting_user.can_access(
Role, 'unattach', role, team_role, 'parents', data={}, skip_sub_obj_read_check=False)}
else:
@@ -1717,22 +1719,22 @@ class CredentialSerializer(BaseSerializer):
res = super(CredentialSerializer, self).get_related(obj)
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
res.update(dict(
activity_stream = reverse('api:credential_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:credential_access_list', args=(obj.pk,)),
object_roles = reverse('api:credential_object_roles_list', args=(obj.pk,)),
owner_users = reverse('api:credential_owner_users_list', args=(obj.pk,)),
owner_teams = reverse('api:credential_owner_teams_list', args=(obj.pk,)),
activity_stream = self.reverse('api:credential_activity_stream_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:credential_access_list', kwargs={'pk': obj.pk}),
object_roles = self.reverse('api:credential_object_roles_list', kwargs={'pk': obj.pk}),
owner_users = self.reverse('api:credential_owner_users_list', kwargs={'pk': obj.pk}),
owner_teams = self.reverse('api:credential_owner_teams_list', kwargs={'pk': obj.pk}),
))
parents = [role for role in obj.admin_role.parents.all() if role.object_id is not None]
if parents:
res.update({parents[0].content_type.name:parents[0].content_object.get_absolute_url()})
res.update({parents[0].content_type.name:parents[0].content_object.get_absolute_url(self.context.get('request'))})
elif len(obj.admin_role.members.all()) > 0:
user = obj.admin_role.members.all()[0]
res.update({'user': reverse('api:user_detail', args=(user.pk,))})
res.update({'user': self.reverse('api:user_detail', kwargs={'pk': user.pk})})
return res
@@ -1746,7 +1748,7 @@ class CredentialSerializer(BaseSerializer):
'type': 'user',
'name': user.username,
'description': ' '.join([user.first_name, user.last_name]),
'url': reverse('api:user_detail', args=(user.pk,)),
'url': self.reverse('api:user_detail', kwargs={'pk': user.pk}),
})
for parent in [role for role in obj.admin_role.parents.all() if role.object_id is not None]:
@@ -1755,7 +1757,7 @@ class CredentialSerializer(BaseSerializer):
'type': camelcase_to_underscore(parent.content_object.__class__.__name__),
'name': parent.content_object.name,
'description': parent.content_object.description,
'url': parent.content_object.get_absolute_url(),
'url': parent.content_object.get_absolute_url(self.context.get('request')),
})
return summary_dict
@@ -1862,19 +1864,19 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
def get_related(self, obj):
res = super(JobOptionsSerializer, self).get_related(obj)
res['labels'] = reverse('api:job_template_label_list', args=(obj.pk,))
res['labels'] = self.reverse('api:job_template_label_list', kwargs={'pk': obj.pk})
if obj.inventory:
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.project:
res['project'] = reverse('api:project_detail', args=(obj.project.pk,))
res['project'] = self.reverse('api:project_detail', kwargs={'pk': obj.project.pk})
if obj.credential:
res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,))
res['credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.credential.pk})
if obj.cloud_credential:
res['cloud_credential'] = reverse('api:credential_detail',
args=(obj.cloud_credential.pk,))
res['cloud_credential'] = self.reverse('api:credential_detail',
kwargs={'pk': obj.cloud_credential.pk})
if obj.network_credential:
res['network_credential'] = reverse('api:credential_detail',
args=(obj.network_credential.pk,))
res['network_credential'] = self.reverse('api:credential_detail',
kwargs={'pk': obj.network_credential.pk})
return res
def to_representation(self, obj):
@@ -1947,20 +1949,20 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
def get_related(self, obj):
res = super(JobTemplateSerializer, self).get_related(obj)
res.update(dict(
jobs = reverse('api:job_template_jobs_list', args=(obj.pk,)),
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,)),
notification_templates_any = reverse('api:job_template_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:job_template_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:job_template_notification_templates_error_list', args=(obj.pk,)),
access_list = reverse('api:job_template_access_list', args=(obj.pk,)),
survey_spec = reverse('api:job_template_survey_spec', args=(obj.pk,)),
labels = reverse('api:job_template_label_list', args=(obj.pk,)),
object_roles = reverse('api:job_template_object_roles_list', args=(obj.pk,)),
jobs = self.reverse('api:job_template_jobs_list', kwargs={'pk': obj.pk}),
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_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}),
survey_spec = self.reverse('api:job_template_survey_spec', kwargs={'pk': obj.pk}),
labels = self.reverse('api:job_template_label_list', kwargs={'pk': obj.pk}),
object_roles = self.reverse('api:job_template_object_roles_list', kwargs={'pk': obj.pk}),
))
if obj.host_config_key:
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))
res['callback'] = self.reverse('api:job_template_callback', kwargs={'pk': obj.pk})
return res
def validate(self, attrs):
@@ -2015,22 +2017,22 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
def get_related(self, obj):
res = super(JobSerializer, self).get_related(obj)
res.update(dict(
job_events = reverse('api:job_job_events_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,)),
labels = reverse('api:job_label_list', args=(obj.pk,)),
job_events = self.reverse('api:job_job_events_list', kwargs={'pk': obj.pk}),
job_host_summaries = self.reverse('api:job_job_host_summaries_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:job_activity_stream_list', kwargs={'pk': obj.pk}),
notifications = self.reverse('api:job_notifications_list', kwargs={'pk': obj.pk}),
labels = self.reverse('api:job_label_list', kwargs={'pk': obj.pk}),
))
if obj.job_template:
res['job_template'] = reverse('api:job_template_detail',
args=(obj.job_template.pk,))
res['job_template'] = self.reverse('api:job_template_detail',
kwargs={'pk': obj.job_template.pk})
if obj.can_start or True:
res['start'] = reverse('api:job_start', args=(obj.pk,))
res['start'] = self.reverse('api:job_start', kwargs={'pk': obj.pk})
if obj.can_cancel or True:
res['cancel'] = reverse('api:job_cancel', args=(obj.pk,))
res['cancel'] = self.reverse('api:job_cancel', kwargs={'pk': obj.pk})
if obj.project_update:
res['project_update'] = reverse('api:project_update_detail', args=(obj.project_update.pk,))
res['relaunch'] = reverse('api:job_relaunch', args=(obj.pk,))
res['project_update'] = self.reverse('api:project_update_detail', kwargs={'pk': obj.project_update.pk})
res['relaunch'] = self.reverse('api:job_relaunch', kwargs={'pk': obj.pk})
return res
def get_artifacts(self, obj):
@@ -2175,16 +2177,16 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
def get_related(self, obj):
res = super(AdHocCommandSerializer, self).get_related(obj)
if obj.inventory:
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.credential:
res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,))
res['credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.credential.pk})
res.update(dict(
events = reverse('api:ad_hoc_command_ad_hoc_command_events_list', args=(obj.pk,)),
activity_stream = reverse('api:ad_hoc_command_activity_stream_list', args=(obj.pk,)),
notifications = reverse('api:ad_hoc_command_notifications_list', args=(obj.pk,)),
events = self.reverse('api:ad_hoc_command_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:ad_hoc_command_activity_stream_list', kwargs={'pk': obj.pk}),
notifications = self.reverse('api:ad_hoc_command_notifications_list', kwargs={'pk': obj.pk}),
))
res['cancel'] = reverse('api:ad_hoc_command_cancel', args=(obj.pk,))
res['relaunch'] = reverse('api:ad_hoc_command_relaunch', args=(obj.pk,))
res['cancel'] = self.reverse('api:ad_hoc_command_cancel', kwargs={'pk': obj.pk})
res['relaunch'] = self.reverse('api:ad_hoc_command_relaunch', kwargs={'pk': obj.pk})
return res
def to_representation(self, obj):
@@ -2229,12 +2231,12 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer):
def get_related(self, obj):
res = super(SystemJobTemplateSerializer, self).get_related(obj)
res.update(dict(
jobs = reverse('api:system_job_template_jobs_list', args=(obj.pk,)),
schedules = reverse('api:system_job_template_schedules_list', args=(obj.pk,)),
launch = reverse('api:system_job_template_launch', args=(obj.pk,)),
notification_templates_any = reverse('api:system_job_template_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:system_job_template_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:system_job_template_notification_templates_error_list', args=(obj.pk,)),
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_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}),
))
return res
@@ -2249,11 +2251,11 @@ class SystemJobSerializer(UnifiedJobSerializer):
def get_related(self, obj):
res = super(SystemJobSerializer, self).get_related(obj)
if obj.system_job_template:
res['system_job_template'] = reverse('api:system_job_template_detail',
args=(obj.system_job_template.pk,))
res['notifications'] = reverse('api:system_job_notifications_list', args=(obj.pk,))
res['system_job_template'] = self.reverse('api:system_job_template_detail',
kwargs={'pk': obj.system_job_template.pk})
res['notifications'] = self.reverse('api:system_job_notifications_list', kwargs={'pk': obj.pk})
if obj.can_cancel or True:
res['cancel'] = reverse('api:system_job_cancel', args=(obj.pk,))
res['cancel'] = self.reverse('api:system_job_cancel', kwargs={'pk': obj.pk})
return res
@@ -2275,22 +2277,22 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
def get_related(self, obj):
res = super(WorkflowJobTemplateSerializer, self).get_related(obj)
res.update(dict(
workflow_jobs = reverse('api:workflow_job_template_jobs_list', args=(obj.pk,)),
schedules = reverse('api:workflow_job_template_schedules_list', args=(obj.pk,)),
launch = reverse('api:workflow_job_template_launch', args=(obj.pk,)),
copy = reverse('api:workflow_job_template_copy', args=(obj.pk,)),
workflow_nodes = reverse('api:workflow_job_template_workflow_nodes_list', args=(obj.pk,)),
labels = reverse('api:workflow_job_template_label_list', args=(obj.pk,)),
activity_stream = reverse('api:workflow_job_template_activity_stream_list', args=(obj.pk,)),
notification_templates_any = reverse('api:workflow_job_template_notification_templates_any_list', args=(obj.pk,)),
notification_templates_success = reverse('api:workflow_job_template_notification_templates_success_list', args=(obj.pk,)),
notification_templates_error = reverse('api:workflow_job_template_notification_templates_error_list', args=(obj.pk,)),
access_list = reverse('api:workflow_job_template_access_list', args=(obj.pk,)),
object_roles = reverse('api:workflow_job_template_object_roles_list', args=(obj.pk,)),
survey_spec = reverse('api:workflow_job_template_survey_spec', args=(obj.pk,)),
workflow_jobs = self.reverse('api:workflow_job_template_jobs_list', kwargs={'pk': obj.pk}),
schedules = self.reverse('api:workflow_job_template_schedules_list', kwargs={'pk': obj.pk}),
launch = self.reverse('api:workflow_job_template_launch', kwargs={'pk': obj.pk}),
copy = self.reverse('api:workflow_job_template_copy', kwargs={'pk': obj.pk}),
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_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}),
object_roles = self.reverse('api:workflow_job_template_object_roles_list', kwargs={'pk': obj.pk}),
survey_spec = self.reverse('api:workflow_job_template_survey_spec', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
def validate_extra_vars(self, value):
@@ -2312,15 +2314,15 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
def get_related(self, obj):
res = super(WorkflowJobSerializer, self).get_related(obj)
if obj.workflow_job_template:
res['workflow_job_template'] = reverse('api:workflow_job_template_detail',
args=(obj.workflow_job_template.pk,))
res['notifications'] = reverse('api:workflow_job_notifications_list', args=(obj.pk,))
res['workflow_nodes'] = reverse('api:workflow_job_workflow_nodes_list', args=(obj.pk,))
res['labels'] = reverse('api:workflow_job_label_list', args=(obj.pk,))
res['activity_stream'] = reverse('api:workflow_job_activity_stream_list', args=(obj.pk,))
res['relaunch'] = reverse('api:workflow_job_relaunch', args=(obj.pk,))
res['workflow_job_template'] = self.reverse('api:workflow_job_template_detail',
kwargs={'pk': obj.workflow_job_template.pk})
res['notifications'] = self.reverse('api:workflow_job_notifications_list', kwargs={'pk': obj.pk})
res['workflow_nodes'] = self.reverse('api:workflow_job_workflow_nodes_list', kwargs={'pk': obj.pk})
res['labels'] = self.reverse('api:workflow_job_label_list', kwargs={'pk': obj.pk})
res['activity_stream'] = self.reverse('api:workflow_job_activity_stream_list', kwargs={'pk': obj.pk})
res['relaunch'] = self.reverse('api:workflow_job_relaunch', kwargs={'pk': obj.pk})
if obj.can_cancel or True:
res['cancel'] = reverse('api:workflow_job_cancel', args=(obj.pk,))
res['cancel'] = self.reverse('api:workflow_job_cancel', kwargs={'pk': obj.pk})
return res
def to_representation(self, obj):
@@ -2362,7 +2364,7 @@ class WorkflowNodeBaseSerializer(BaseSerializer):
def get_related(self, obj):
res = super(WorkflowNodeBaseSerializer, self).get_related(obj)
if obj.unified_job_template:
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(self.context.get('request'))
return res
def validate(self, attrs):
@@ -2380,11 +2382,11 @@ class WorkflowJobTemplateNodeSerializer(WorkflowNodeBaseSerializer):
def get_related(self, obj):
res = super(WorkflowJobTemplateNodeSerializer, self).get_related(obj)
res['success_nodes'] = reverse('api:workflow_job_template_node_success_nodes_list', args=(obj.pk,))
res['failure_nodes'] = reverse('api:workflow_job_template_node_failure_nodes_list', args=(obj.pk,))
res['always_nodes'] = reverse('api:workflow_job_template_node_always_nodes_list', args=(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})
if obj.workflow_job_template:
res['workflow_job_template'] = reverse('api:workflow_job_template_detail', args=(obj.workflow_job_template.pk,))
res['workflow_job_template'] = self.reverse('api:workflow_job_template_detail', kwargs={'pk': obj.workflow_job_template.pk})
return res
def to_internal_value(self, data):
@@ -2440,13 +2442,13 @@ class WorkflowJobNodeSerializer(WorkflowNodeBaseSerializer):
def get_related(self, obj):
res = super(WorkflowJobNodeSerializer, self).get_related(obj)
res['success_nodes'] = reverse('api:workflow_job_node_success_nodes_list', args=(obj.pk,))
res['failure_nodes'] = reverse('api:workflow_job_node_failure_nodes_list', args=(obj.pk,))
res['always_nodes'] = reverse('api:workflow_job_node_always_nodes_list', args=(obj.pk,))
res['success_nodes'] = self.reverse('api:workflow_job_node_success_nodes_list', kwargs={'pk': obj.pk})
res['failure_nodes'] = self.reverse('api:workflow_job_node_failure_nodes_list', kwargs={'pk': obj.pk})
res['always_nodes'] = self.reverse('api:workflow_job_node_always_nodes_list', kwargs={'pk': obj.pk})
if obj.job:
res['job'] = obj.job.get_absolute_url()
res['job'] = obj.job.get_absolute_url(self.context.get('request'))
if obj.workflow_job:
res['workflow_job'] = reverse('api:workflow_job_detail', args=(obj.workflow_job.pk,))
res['workflow_job'] = self.reverse('api:workflow_job_detail', kwargs={'pk': obj.workflow_job.pk})
return res
@@ -2500,10 +2502,10 @@ class JobHostSummarySerializer(BaseSerializer):
def get_related(self, obj):
res = super(JobHostSummarySerializer, self).get_related(obj)
res.update(dict(
job=reverse('api:job_detail', args=(obj.job.pk,))))
job=self.reverse('api:job_detail', kwargs={'pk': obj.job.pk})))
if obj.host is not None:
res.update(dict(
host=reverse('api:host_detail', args=(obj.host.pk,))
host=self.reverse('api:host_detail', kwargs={'pk': obj.host.pk})
))
return res
@@ -2533,16 +2535,16 @@ class JobEventSerializer(BaseSerializer):
def get_related(self, obj):
res = super(JobEventSerializer, self).get_related(obj)
res.update(dict(
job = reverse('api:job_detail', args=(obj.job_id,)),
job = self.reverse('api:job_detail', kwargs={'pk': obj.job_id}),
))
if obj.parent_id:
res['parent'] = reverse('api:job_event_detail', args=(obj.parent_id,))
res['parent'] = self.reverse('api:job_event_detail', kwargs={'pk': obj.parent_id})
if obj.children.exists():
res['children'] = reverse('api:job_event_children_list', args=(obj.pk,))
res['children'] = self.reverse('api:job_event_children_list', kwargs={'pk': obj.pk})
if obj.host_id:
res['host'] = reverse('api:host_detail', args=(obj.host_id,))
res['host'] = self.reverse('api:host_detail', kwargs={'pk': obj.host_id})
if obj.hosts.exists():
res['hosts'] = reverse('api:job_event_hosts_list', args=(obj.pk,))
res['hosts'] = self.reverse('api:job_event_hosts_list', kwargs={'pk': obj.pk})
return res
def get_summary_fields(self, obj):
@@ -2582,10 +2584,10 @@ class AdHocCommandEventSerializer(BaseSerializer):
def get_related(self, obj):
res = super(AdHocCommandEventSerializer, self).get_related(obj)
res.update(dict(
ad_hoc_command = reverse('api:ad_hoc_command_detail', args=(obj.ad_hoc_command_id,)),
ad_hoc_command = self.reverse('api:ad_hoc_command_detail', kwargs={'pk': obj.ad_hoc_command_id}),
))
if obj.host:
res['host'] = reverse('api:host_detail', args=(obj.host.pk,))
res['host'] = self.reverse('api:host_detail', kwargs={'pk': obj.host.pk})
return res
def to_representation(self, obj):
@@ -2809,11 +2811,11 @@ class NotificationTemplateSerializer(BaseSerializer):
def get_related(self, obj):
res = super(NotificationTemplateSerializer, self).get_related(obj)
res.update(dict(
test = reverse('api:notification_template_test', args=(obj.pk,)),
notifications = reverse('api:notification_template_notification_list', args=(obj.pk,)),
test = self.reverse('api:notification_template_test', kwargs={'pk': obj.pk}),
notifications = self.reverse('api:notification_template_notification_list', kwargs={'pk': obj.pk}),
))
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
def _recent_notifications(self, obj):
@@ -2883,7 +2885,7 @@ class NotificationSerializer(BaseSerializer):
def get_related(self, obj):
res = super(NotificationSerializer, self).get_related(obj)
res.update(dict(
notification_template = reverse('api:notification_template_detail', args=(obj.notification_template.pk,)),
notification_template = self.reverse('api:notification_template_detail', kwargs={'pk': obj.notification_template.pk}),
))
return res
@@ -2897,7 +2899,7 @@ class LabelSerializer(BaseSerializer):
def get_related(self, obj):
res = super(LabelSerializer, self).get_related(obj)
if obj.organization:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
@@ -2911,10 +2913,10 @@ 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 = self.reverse('api:schedule_unified_jobs_list', kwargs={'pk': obj.pk}),
))
if obj.unified_job_template:
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
res['unified_job_template'] = obj.unified_job_template.get_absolute_url(self.context.get('request'))
return res
def validate_unified_job_template(self, value):
@@ -3038,7 +3040,7 @@ class ActivityStreamSerializer(BaseSerializer):
def get_related(self, obj):
rel = {}
if obj.actor is not None:
rel['actor'] = reverse('api:user_detail', args=(obj.actor.pk,))
rel['actor'] = self.reverse('api:user_detail', kwargs={'pk': obj.actor.pk})
for fk, __ in self._local_summarizable_fk_fields:
if not hasattr(obj, fk):
continue
@@ -3051,12 +3053,12 @@ class ActivityStreamSerializer(BaseSerializer):
continue
id_list.append(getattr(thisItem, 'id', None))
if fk == 'custom_inventory_script':
rel[fk].append(reverse('api:inventory_script_detail', args=(thisItem.id,)))
rel[fk].append(self.reverse('api:inventory_script_detail', kwargs={'pk': thisItem.id}))
else:
rel[fk].append(reverse('api:' + fk + '_detail', args=(thisItem.id,)))
rel[fk].append(self.reverse('api:' + fk + '_detail', kwargs={'pk': thisItem.id}))
if fk == 'schedule':
rel['unified_job_template'] = thisItem.unified_job_template.get_absolute_url()
rel['unified_job_template'] = thisItem.unified_job_template.get_absolute_url(self.context.get('request'))
return rel
def get_summary_fields(self, obj):
@@ -3137,7 +3139,10 @@ class FactVersionSerializer(BaseFactSerializer):
'datetime': timestamp_apiformat(obj.timestamp),
'module': obj.module,
}
res['fact_view'] = build_url('api:host_fact_compare_view', args=(obj.host.pk,), get=params)
res['fact_view'] = '%s?%s' % (
reverse('api:host_fact_compare_view', kwargs={'pk': obj.host.pk}, request=self.context.get('request')),
urllib.urlencode(params)
)
return res
@@ -3151,7 +3156,7 @@ class FactSerializer(BaseFactSerializer):
def get_related(self, obj):
res = super(FactSerializer, self).get_related(obj)
res['host'] = obj.host.get_absolute_url()
res['host'] = obj.host.get_absolute_url(self.context.get('request'))
return res
def to_representation(self, obj):

View File

@@ -9,5 +9,6 @@
{% if new_in_240 %}> _Added in Ansible Tower 2.4.0_{% endif %}
{% if new_in_300 %}> _Added in Ansible Tower 3.0.0_{% endif %}
{% if new_in_310 %}> _New in Ansible Tower 3.1.0_{% endif %}
{% if new_in_320 %}> _New in Ansible Tower 3.2.0_{% endif %}
{% if deprecated %}> _This resource has been deprecated and will be removed in a future release_{% endif %}
{% endif %}

View File

@@ -331,7 +331,7 @@ activity_stream_urls = patterns('awx.api.views',
)
v1_urls = patterns('awx.api.views',
url(r'^$', 'api_v1_root_view'),
url(r'^$', 'api_version_root_view'),
url(r'^ping/$', 'api_v1_ping_view'),
url(r'^config/$', 'api_v1_config_view'),
url(r'^auth/$', 'auth_view'),
@@ -376,5 +376,5 @@ v1_urls = patterns('awx.api.views',
urlpatterns = patterns('awx.api.views',
url(r'^$', 'api_root_view'),
url(r'^v1/', include(v1_urls)),
url(r'^(?P<version>(v1|v2))/', include(v1_urls))
)

30
awx/api/versioning.py Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) 2017 Ansible by Red Hat
# All Rights Reserved.
from rest_framework.reverse import reverse as drf_reverse
from rest_framework.versioning import URLPathVersioning as BaseVersioning
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request is None or getattr(request, 'version', None) is None:
# We need the "current request" to determine the correct version to
# prepend to reverse URLs. If there is no "current request", assume
# the latest API version.
if kwargs is None:
kwargs = {}
if 'version' not in kwargs:
kwargs['version'] = 'v2'
return drf_reverse(viewname, args, kwargs, request, format, **extra)
class URLPathVersioning(BaseVersioning):
def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request.version is not None:
kwargs = {} if (kwargs is None) else kwargs
kwargs[self.version_param] = request.version
request = None
return super(BaseVersioning, self).reverse(
viewname, args, kwargs, request, format, **extra
)

View File

@@ -20,7 +20,6 @@ from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User, AnonymousUser
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.core.exceptions import FieldError
from django.db.models import Q, Count, F
from django.db import IntegrityError, transaction, connection
@@ -65,6 +64,7 @@ from awx.main.ha import is_ha_environment
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
from awx.api.generics import get_view_name
from awx.api.generics import * # noqa
from awx.api.versioning import reverse
from awx.conf.license import get_license, feature_enabled, feature_exists, LicenseForbids
from awx.main.models import * # noqa
from awx.main.utils import * # noqa
@@ -128,17 +128,17 @@ class ApiRootView(APIView):
authentication_classes = []
permission_classes = (AllowAny,)
view_name = _('REST API')
versioning_class = None
def get(self, request, format=None):
''' list supported API versions '''
current = reverse('api:api_v1_root_view', args=[])
v1 = reverse('api:api_version_root_view', kwargs={'version': 'v1'})
v2 = reverse('api:api_version_root_view', kwargs={'version': 'v2'})
data = dict(
description = _('Ansible Tower REST API'),
current_version = current,
available_versions = dict(
v1 = current
),
current_version = v2,
available_versions = dict(v1 = v1, v2 = v2),
)
if feature_enabled('rebranding'):
data['custom_logo'] = settings.CUSTOM_LOGO
@@ -146,52 +146,52 @@ class ApiRootView(APIView):
return Response(data)
class ApiV1RootView(APIView):
class ApiVersionRootView(APIView):
authentication_classes = []
view_name = _('Version')
permission_classes = (AllowAny,)
view_name = _('Version 1')
def get(self, request, format=None):
''' list top level resources '''
data = OrderedDict()
data['authtoken'] = reverse('api:auth_token_view')
data['ping'] = reverse('api:api_v1_ping_view')
data['config'] = reverse('api:api_v1_config_view')
data['settings'] = reverse('api:setting_category_list')
data['me'] = reverse('api:user_me_list')
data['dashboard'] = reverse('api:dashboard_view')
data['organizations'] = reverse('api:organization_list')
data['users'] = reverse('api:user_list')
data['projects'] = reverse('api:project_list')
data['project_updates'] = reverse('api:project_update_list')
data['teams'] = reverse('api:team_list')
data['credentials'] = reverse('api:credential_list')
data['inventory'] = reverse('api:inventory_list')
data['inventory_scripts'] = reverse('api:inventory_script_list')
data['inventory_sources'] = reverse('api:inventory_source_list')
data['inventory_updates'] = reverse('api:inventory_update_list')
data['groups'] = reverse('api:group_list')
data['hosts'] = reverse('api:host_list')
data['job_templates'] = reverse('api:job_template_list')
data['jobs'] = reverse('api:job_list')
data['job_events'] = reverse('api:job_event_list')
data['ad_hoc_commands'] = reverse('api:ad_hoc_command_list')
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['roles'] = reverse('api:role_list')
data['notification_templates'] = reverse('api:notification_template_list')
data['notifications'] = reverse('api:notification_list')
data['labels'] = reverse('api:label_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')
data['workflow_job_templates'] = reverse('api:workflow_job_template_list')
data['workflow_jobs'] = reverse('api:workflow_job_list')
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list')
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list')
data['authtoken'] = reverse('api:auth_token_view', request=request)
data['ping'] = reverse('api:api_v1_ping_view', request=request)
data['config'] = reverse('api:api_v1_config_view', request=request)
data['settings'] = reverse('api:setting_category_list', request=request)
data['me'] = reverse('api:user_me_list', request=request)
data['dashboard'] = reverse('api:dashboard_view', request=request)
data['organizations'] = reverse('api:organization_list', request=request)
data['users'] = reverse('api:user_list', request=request)
data['projects'] = reverse('api:project_list', request=request)
data['project_updates'] = reverse('api:project_update_list', request=request)
data['teams'] = reverse('api:team_list', request=request)
data['credentials'] = reverse('api:credential_list', request=request)
data['inventory'] = reverse('api:inventory_list', request=request)
data['inventory_scripts'] = reverse('api:inventory_script_list', request=request)
data['inventory_sources'] = reverse('api:inventory_source_list', request=request)
data['inventory_updates'] = reverse('api:inventory_update_list', request=request)
data['groups'] = reverse('api:group_list', request=request)
data['hosts'] = reverse('api:host_list', request=request)
data['job_templates'] = reverse('api:job_template_list', request=request)
data['jobs'] = reverse('api:job_list', request=request)
data['job_events'] = reverse('api:job_event_list', request=request)
data['ad_hoc_commands'] = reverse('api:ad_hoc_command_list', request=request)
data['system_job_templates'] = reverse('api:system_job_template_list', request=request)
data['system_jobs'] = reverse('api:system_job_list', request=request)
data['schedules'] = reverse('api:schedule_list', request=request)
data['roles'] = reverse('api:role_list', request=request)
data['notification_templates'] = reverse('api:notification_template_list', request=request)
data['notifications'] = reverse('api:notification_list', request=request)
data['labels'] = reverse('api:label_list', request=request)
data['unified_job_templates'] = reverse('api:unified_job_template_list', request=request)
data['unified_jobs'] = reverse('api:unified_job_list', request=request)
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_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
return Response(data)
@@ -336,12 +336,12 @@ class DashboardView(APIView):
def get(self, request, format=None):
''' Show Dashboard Details '''
data = OrderedDict()
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view')}
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view', request=request)}
user_inventory = get_user_queryset(request.user, Inventory)
inventory_with_failed_hosts = user_inventory.filter(hosts_with_active_failures__gt=0)
user_inventory_external = user_inventory.filter(has_inventory_sources=True)
failed_inventory = sum(i.inventory_sources_with_failures for i in user_inventory)
data['inventories'] = {'url': reverse('api:inventory_list'),
data['inventories'] = {'url': reverse('api:inventory_list', request=request),
'total': user_inventory.count(),
'total_with_inventory_source': user_inventory_external.count(),
'job_failed': inventory_with_failed_hosts.count(),
@@ -352,13 +352,13 @@ class DashboardView(APIView):
ec2_inventory_sources = user_inventory_sources.filter(source='ec2')
ec2_inventory_failed = ec2_inventory_sources.filter(status='failed')
data['inventory_sources'] = {}
data['inventory_sources']['rax'] = {'url': reverse('api:inventory_source_list') + "?source=rax",
data['inventory_sources']['rax'] = {'url': reverse('api:inventory_source_list', request=request) + "?source=rax",
'label': 'Rackspace',
'failures_url': reverse('api:inventory_source_list') + "?source=rax&status=failed",
'failures_url': reverse('api:inventory_source_list', request=request) + "?source=rax&status=failed",
'total': rax_inventory_sources.count(),
'failed': rax_inventory_failed.count()}
data['inventory_sources']['ec2'] = {'url': reverse('api:inventory_source_list') + "?source=ec2",
'failures_url': reverse('api:inventory_source_list') + "?source=ec2&status=failed",
data['inventory_sources']['ec2'] = {'url': reverse('api:inventory_source_list', request=request) + "?source=ec2",
'failures_url': reverse('api:inventory_source_list', request=request) + "?source=ec2&status=failed",
'label': 'Amazon EC2',
'total': ec2_inventory_sources.count(),
'failed': ec2_inventory_failed.count()}
@@ -366,23 +366,23 @@ class DashboardView(APIView):
user_groups = get_user_queryset(request.user, Group)
groups_job_failed = (Group.objects.filter(hosts_with_active_failures__gt=0) | Group.objects.filter(groups_with_active_failures__gt=0)).count()
groups_inventory_failed = Group.objects.filter(inventory_sources__last_job_failed=True).count()
data['groups'] = {'url': reverse('api:group_list'),
'failures_url': reverse('api:group_list') + "?has_active_failures=True",
data['groups'] = {'url': reverse('api:group_list', request=request),
'failures_url': reverse('api:group_list', request=request) + "?has_active_failures=True",
'total': user_groups.count(),
'job_failed': groups_job_failed,
'inventory_failed': groups_inventory_failed}
user_hosts = get_user_queryset(request.user, Host)
user_hosts_failed = user_hosts.filter(has_active_failures=True)
data['hosts'] = {'url': reverse('api:host_list'),
'failures_url': reverse('api:host_list') + "?has_active_failures=True",
data['hosts'] = {'url': reverse('api:host_list', request=request),
'failures_url': reverse('api:host_list', request=request) + "?has_active_failures=True",
'total': user_hosts.count(),
'failed': user_hosts_failed.count()}
user_projects = get_user_queryset(request.user, Project)
user_projects_failed = user_projects.filter(last_job_failed=True)
data['projects'] = {'url': reverse('api:project_list'),
'failures_url': reverse('api:project_list') + "?last_job_failed=True",
data['projects'] = {'url': reverse('api:project_list', request=request),
'failures_url': reverse('api:project_list', request=request) + "?last_job_failed=True",
'total': user_projects.count(),
'failed': user_projects_failed.count()}
@@ -393,26 +393,26 @@ class DashboardView(APIView):
hg_projects = user_projects.filter(scm_type='hg')
hg_failed_projects = hg_projects.filter(last_job_failed=True)
data['scm_types'] = {}
data['scm_types']['git'] = {'url': reverse('api:project_list') + "?scm_type=git",
data['scm_types']['git'] = {'url': reverse('api:project_list', request=request) + "?scm_type=git",
'label': 'Git',
'failures_url': reverse('api:project_list') + "?scm_type=git&last_job_failed=True",
'failures_url': reverse('api:project_list', request=request) + "?scm_type=git&last_job_failed=True",
'total': git_projects.count(),
'failed': git_failed_projects.count()}
data['scm_types']['svn'] = {'url': reverse('api:project_list') + "?scm_type=svn",
data['scm_types']['svn'] = {'url': reverse('api:project_list', request=request) + "?scm_type=svn",
'label': 'Subversion',
'failures_url': reverse('api:project_list') + "?scm_type=svn&last_job_failed=True",
'failures_url': reverse('api:project_list', request=request) + "?scm_type=svn&last_job_failed=True",
'total': svn_projects.count(),
'failed': svn_failed_projects.count()}
data['scm_types']['hg'] = {'url': reverse('api:project_list') + "?scm_type=hg",
data['scm_types']['hg'] = {'url': reverse('api:project_list', request=request) + "?scm_type=hg",
'label': 'Mercurial',
'failures_url': reverse('api:project_list') + "?scm_type=hg&last_job_failed=True",
'failures_url': reverse('api:project_list', request=request) + "?scm_type=hg&last_job_failed=True",
'total': hg_projects.count(),
'failed': hg_failed_projects.count()}
user_jobs = get_user_queryset(request.user, Job)
user_failed_jobs = user_jobs.filter(failed=True)
data['jobs'] = {'url': reverse('api:job_list'),
'failure_url': reverse('api:job_list') + "?failed=True",
data['jobs'] = {'url': reverse('api:job_list', request=request),
'failure_url': reverse('api:job_list', request=request) + "?failed=True",
'total': user_jobs.count(),
'failed': user_failed_jobs.count()}
@@ -421,15 +421,15 @@ class DashboardView(APIView):
credential_list = get_user_queryset(request.user, Credential)
job_template_list = get_user_queryset(request.user, JobTemplate)
organization_list = get_user_queryset(request.user, Organization)
data['users'] = {'url': reverse('api:user_list'),
data['users'] = {'url': reverse('api:user_list', request=request),
'total': user_list.count()}
data['organizations'] = {'url': reverse('api:organization_list'),
data['organizations'] = {'url': reverse('api:organization_list', request=request),
'total': organization_list.count()}
data['teams'] = {'url': reverse('api:team_list'),
data['teams'] = {'url': reverse('api:team_list', request=request),
'total': team_list.count()}
data['credentials'] = {'url': reverse('api:credential_list'),
data['credentials'] = {'url': reverse('api:credential_list', request=request),
'total': credential_list.count()}
data['job_templates'] = {'url': reverse('api:job_template_list'),
data['job_templates'] = {'url': reverse('api:job_template_list', request=request),
'total': job_template_list.count()}
return Response(data)
@@ -516,6 +516,7 @@ class AuthView(APIView):
new_in_240 = True
def get(self, request):
from rest_framework.reverse import reverse
data = OrderedDict()
err_backend, err_message = request.session.get('social_auth_error', (None, None))
auth_backends = load_backends(settings.AUTHENTICATION_BACKENDS, force_load=True).items()
@@ -527,6 +528,7 @@ class AuthView(APIView):
(not feature_enabled('enterprise_auth') and
name in ['saml', 'radius']):
continue
login_url = reverse('social:begin', args=(name,))
complete_url = request.build_absolute_uri(reverse('social:complete', args=(name,)))
backend_data = {
@@ -1167,7 +1169,7 @@ class ProjectUpdateView(RetrieveAPIView):
if not project_update:
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
headers = {'Location': project_update.get_absolute_url()}
headers = {'Location': project_update.get_absolute_url(request=request)}
return Response({'project_update': project_update.id},
headers=headers,
status=status.HTTP_202_ACCEPTED)
@@ -2273,7 +2275,7 @@ class InventorySourceUpdateView(RetrieveAPIView):
if not inventory_update:
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
headers = {'Location': inventory_update.get_absolute_url()}
headers = {'Location': inventory_update.get_absolute_url(request=request)}
return Response(dict(inventory_update=inventory_update.id), status=status.HTTP_202_ACCEPTED, headers=headers)
else:
return self.http_method_not_allowed(request, *args, **kwargs)
@@ -2741,7 +2743,7 @@ class JobTemplateCallback(GenericAPIView):
return Response(data, status=status.HTTP_400_BAD_REQUEST)
# Return the location of the new job.
headers = {'Location': job.get_absolute_url()}
headers = {'Location': job.get_absolute_url(request=request)}
return Response(status=status.HTTP_201_CREATED, headers=headers)
@@ -3035,7 +3037,7 @@ class WorkflowJobRelaunch(WorkflowsEnforcementMixin, GenericAPIView):
new_workflow_job.signal_start()
data = WorkflowJobSerializer(new_workflow_job, context=self.get_serializer_context()).data
headers = {'Location': new_workflow_job.get_absolute_url()}
headers = {'Location': new_workflow_job.get_absolute_url(request=request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
@@ -3419,7 +3421,7 @@ class JobRelaunch(RetrieveAPIView, GenericAPIView):
data = JobSerializer(new_job, context=self.get_serializer_context()).data
# Add job key to match what old relaunch returned.
data['job'] = new_job.id
headers = {'Location': new_job.get_absolute_url()}
headers = {'Location': new_job.get_absolute_url(request=request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
@@ -3693,7 +3695,7 @@ class AdHocCommandRelaunch(GenericAPIView):
data = AdHocCommandSerializer(new_ad_hoc_command, context=self.get_serializer_context()).data
# Add ad_hoc_command key to match what was previously returned.
data['ad_hoc_command'] = new_ad_hoc_command.id
headers = {'Location': new_ad_hoc_command.get_absolute_url()}
headers = {'Location': new_ad_hoc_command.get_absolute_url(request=request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
@@ -3994,7 +3996,7 @@ class NotificationTemplateTest(GenericAPIView):
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
send_notifications.delay([notification.id])
headers = {'Location': notification.get_absolute_url()}
headers = {'Location': notification.get_absolute_url(request=request)}
return Response({"notification": notification.id},
headers=headers,
status=status.HTTP_202_ACCEPTED)