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)

View File

@ -7,7 +7,6 @@ import sys
# Django
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
@ -20,6 +19,7 @@ from rest_framework import status
# Tower
from awx.api.generics import * # noqa
from awx.api.permissions import IsSuperUser
from awx.api.versioning import reverse
from awx.main.utils import * # noqa
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
from awx.conf.license import get_licensed_features
@ -49,7 +49,7 @@ class SettingCategoryList(ListAPIView):
else:
categories = {}
for category_slug in sorted(categories.keys()):
url = reverse('api:setting_singleton_detail', args=(category_slug,))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': category_slug}, request=self.request)
setting_categories.append(SettingCategory(url, category_slug, categories[category_slug]))
return setting_categories

View File

@ -1,9 +1,11 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
# Tower
from awx.api.versioning import reverse
# Django
from django.db import models
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
__all__ = ['ActivityStream']
@ -63,8 +65,8 @@ class ActivityStream(models.Model):
label = models.ManyToManyField("Label", blank=True)
role = models.ManyToManyField("Role", blank=True)
def get_absolute_url(self):
return reverse('api:activity_stream_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:activity_stream_detail', kwargs={'pk': self.pk}, request=request)
def save(self, *args, **kwargs):
# For compatibility with Django 1.4.x, attempt to handle any calls to

View File

@ -16,9 +16,9 @@ from django.utils.text import Truncator
from django.utils.timezone import utc
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import * # noqa
from awx.main.models.unified_jobs import * # noqa
from awx.main.models.notifications import JobNotificationMixin, NotificationTemplate
@ -143,8 +143,8 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
from awx.main.tasks import RunAdHocCommand
return RunAdHocCommand
def get_absolute_url(self):
return reverse('api:ad_hoc_command_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:ad_hoc_command_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, "/#/ad_hoc_commands/{}".format(self.pk))
@ -318,8 +318,8 @@ class AdHocCommandEvent(CreatedModifiedModel):
editable=False,
)
def get_absolute_url(self):
return reverse('api:ad_hoc_command_event_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:ad_hoc_command_event_detail', kwargs={'pk': self.pk}, request=request)
def __unicode__(self):
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())

View File

@ -5,9 +5,9 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
# AWX
from awx.api.versioning import reverse
from awx.main.fields import ImplicitRoleField
from awx.main.constants import CLOUD_PROVIDERS
from awx.main.utils import decrypt_field
@ -271,8 +271,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
needed.append(field)
return needed
def get_absolute_url(self):
return reverse('api:credential_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:credential_detail', kwargs={'pk': self.pk}, request=request)
def clean_host(self):
"""Ensure that if this is a type of credential that requires a

View File

@ -14,10 +14,10 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.db import transaction
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.utils.timezone import now
# AWX
from awx.api.versioning import reverse
from awx.main.constants import CLOUD_PROVIDERS
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
from awx.main.managers import HostManager
@ -117,9 +117,8 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
'admin_role',
])
def get_absolute_url(self):
return reverse('api:inventory_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:inventory_detail', kwargs={'pk': self.pk}, request=request)
variables_dict = VarsDictProperty('variables')
@ -389,8 +388,8 @@ class Host(CommonModelNameNotUnique):
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('api:host_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:host_detail', kwargs={'pk': self.pk}, request=request)
def update_computed_fields(self, update_inventory=True, update_groups=True):
'''
@ -520,8 +519,8 @@ class Group(CommonModelNameNotUnique):
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse('api:group_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:group_detail', kwargs={'pk': self.pk}, request=request)
@transaction.atomic
def delete_recursive(self):
@ -1137,8 +1136,8 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
else:
return 'none'
def get_absolute_url(self):
return reverse('api:inventory_source_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:inventory_source_detail', kwargs={'pk': self.pk}, request=request)
def _can_update(self):
if self.source == 'custom':
@ -1246,8 +1245,8 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin):
update_fields.append('name')
super(InventoryUpdate, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('api:inventory_update_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:inventory_update_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, "/#/inventory_sync/{}".format(self.pk))
@ -1322,5 +1321,5 @@ class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin):
parent_role=['organization.auditor_role', 'organization.member_role', 'admin_role'],
)
def get_absolute_url(self):
return reverse('api:inventory_script_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request)

View File

@ -18,9 +18,9 @@ from django.utils.encoding import force_text
from django.utils.timezone import utc
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
# AWX
from awx.api.versioning import reverse
from awx.main.constants import CLOUD_PROVIDERS
from awx.main.models.base import * # noqa
from awx.main.models.unified_jobs import * # noqa
@ -293,8 +293,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
'''
return self.create_unified_job(**kwargs)
def get_absolute_url(self):
return reverse('api:job_template_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:job_template_detail', kwargs={'pk': self.pk}, request=request)
def can_start_without_user_input(self, callback_extra_vars=None):
'''
@ -471,8 +471,8 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
def _get_unified_job_template_class(cls):
return JobTemplate
def get_absolute_url(self):
return reverse('api:job_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:job_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, "/#/jobs/{}".format(self.pk))
@ -688,8 +688,8 @@ class JobHostSummary(CreatedModifiedModel):
(self.host.name, self.changed, self.dark, self.failures, self.ok,
self.processed, self.skipped)
def get_absolute_url(self):
return reverse('api:job_host_summary_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:job_host_summary_detail', kwargs={'pk': self.pk}, request=request)
def save(self, *args, **kwargs):
# If update_fields has been specified, add our field names to it,
@ -906,8 +906,8 @@ class JobEvent(CreatedModifiedModel):
editable=False,
)
def get_absolute_url(self):
return reverse('api:job_event_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:job_event_detail', kwargs={'pk': self.pk}, request=request)
def __unicode__(self):
return u'%s @ %s' % (self.get_event_display2(), self.created.isoformat())
@ -1220,8 +1220,8 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
def _get_unified_job_field_names(cls):
return ['name', 'description', 'job_type', 'extra_vars']
def get_absolute_url(self):
return reverse('api:system_job_template_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:system_job_template_detail', kwargs={'pk': self.pk}, request=request)
@property
def cache_timeout_blocked(self):
@ -1276,8 +1276,8 @@ class SystemJob(UnifiedJob, SystemJobOptions, JobNotificationMixin):
def websocket_emit_data(self):
return {}
def get_absolute_url(self):
return reverse('api:system_job_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:system_job_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, "/#/management_jobs/{}".format(self.pk))

View File

@ -3,10 +3,10 @@
# Django
from django.db import models
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import CommonModelNameNotUnique
from awx.main.models.unified_jobs import UnifiedJobTemplate, UnifiedJob
@ -30,8 +30,8 @@ class Label(CommonModelNameNotUnique):
on_delete=models.CASCADE,
)
def get_absolute_url(self):
return reverse('api:label_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:label_detail', kwargs={'pk': self.pk}, request=request)
@staticmethod
def get_orphaned_labels():

View File

@ -4,11 +4,12 @@
import logging
from django.db import models
from django.core.urlresolvers import reverse
from django.core.mail.message import EmailMessage
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_str
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import * # noqa
from awx.main.utils import encrypt_field, decrypt_field
from awx.main.notifications.email_backend import CustomEmailBackend
@ -56,8 +57,8 @@ class NotificationTemplate(CommonModel):
notification_configuration = JSONField(blank=False)
def get_absolute_url(self):
return reverse('api:notification_template_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:notification_template_detail', kwargs={'pk': self.pk}, request=request)
@property
def notification_class(self):
@ -169,9 +170,9 @@ class Notification(CreatedModifiedModel):
editable=False,
)
body = JSONField(blank=True)
def get_absolute_url(self):
return reverse('api:notification_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:notification_detail', kwargs={'pk': self.pk}, request=request)
class JobNotificationMixin(object):

View File

@ -10,12 +10,12 @@ import uuid
# Django
from django.conf import settings
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.utils.timezone import now as tz_now
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.api.versioning import reverse
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
from awx.main.models.base import * # noqa
from awx.main.models.rbac import (
@ -65,8 +65,8 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
)
def get_absolute_url(self):
return reverse('api:organization_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:organization_detail', kwargs={'pk': self.pk}, request=request)
def __unicode__(self):
return self.name
@ -109,8 +109,8 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
parent_role=['organization.auditor_role', 'member_role'],
)
def get_absolute_url(self):
return reverse('api:team_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:team_detail', kwargs={'pk': self.pk}, request=request)
class Permission(CommonModelNameNotUnique):
@ -167,8 +167,8 @@ class Permission(CommonModelNameNotUnique):
'+adhoc' if self.run_ad_hoc_commands else '',
))
def get_absolute_url(self):
return reverse('api:permission_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:permission_detail', kwargs={'pk': self.pk}, request=request)
class Profile(CreatedModifiedModel):
@ -326,6 +326,6 @@ class AuthToken(BaseModel):
# Add get_absolute_url method to User model if not present.
if not hasattr(User, 'get_absolute_url'):
def user_get_absolute_url(user):
return reverse('api:user_detail', args=(user.pk,))
def user_get_absolute_url(user, request=None):
return reverse('api:user_detail', kwargs={'pk': user.pk}, request=request)
User.add_to_class('get_absolute_url', user_get_absolute_url)

View File

@ -14,10 +14,10 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_str, smart_text
from django.utils.text import slugify
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.utils.timezone import now, make_aware, get_default_timezone
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import * # noqa
from awx.main.models.notifications import (
NotificationTemplate,
@ -401,8 +401,8 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
success=list(success_notification_templates),
any=list(any_notification_templates))
def get_absolute_url(self):
return reverse('api:project_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:project_detail', kwargs={'pk': self.pk}, request=request)
class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
@ -470,8 +470,8 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
def result_stdout_limited(self, start_line=0, end_line=None, redact_sensitive=True):
return self._result_stdout_raw_limited(start_line, end_line, redact_sensitive=redact_sensitive, escape_ascii=True)
def get_absolute_url(self):
return reverse('api:project_update_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:project_update_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urlparse.urljoin(settings.TOWER_URL_BASE, "/#/scm_update/{}".format(self.pk))

View File

@ -9,13 +9,12 @@ import re
# Django
from django.db import models, transaction, connection
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.api.versioning import reverse
from django.contrib.auth.models import User # noqa
from awx.main.models.base import * # noqa
@ -145,8 +144,8 @@ class Role(models.Model):
super(Role, self).save(*args, **kwargs)
self.rebuild_role_ancestor_list([self.id], [])
def get_absolute_url(self):
return reverse('api:role_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:role_detail', kwargs={'pk': self.pk}, request=request)
def __contains__(self, accessor):
if type(accessor) == User:

View File

@ -13,10 +13,10 @@ from django.utils.timezone import now, make_aware, get_default_timezone
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import * # noqa
from awx.main.utils import ignore_inventory_computed_fields
from awx.main.consumers import emit_channel_notification
from django.core.urlresolvers import reverse
from awx.main.fields import JSONField
logger = logging.getLogger('awx.main.models.schedule')
@ -98,8 +98,8 @@ class Schedule(CommonModel):
def __unicode__(self):
return u'%s_t%s_%s_%s' % (self.name, self.unified_job_template.id, self.id, self.next_run)
def get_absolute_url(self):
return reverse('api:schedule_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:schedule_detail', kwargs={'pk': self.pk}, request=request)
def update_computed_fields(self):
future_rs = dateutil.rrule.rrulestr(self.rrule, forceset=True)

View File

@ -153,10 +153,10 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
related_name='%(class)s_labels'
)
def get_absolute_url(self):
def get_absolute_url(self, request=None):
real_instance = self.get_real_instance()
if real_instance != self:
return real_instance.get_absolute_url()
return real_instance.get_absolute_url(request=request)
else:
return ''

View File

@ -7,10 +7,10 @@
# Django
from django.db import models
from django.conf import settings
from django.core.urlresolvers import reverse
#from django import settings as tower_settings
# AWX
from awx.api.versioning import reverse
from awx.main.models import prevent_search, UnifiedJobTemplate, UnifiedJob
from awx.main.models.notifications import (
NotificationTemplate,
@ -177,8 +177,8 @@ class WorkflowJobTemplateNode(WorkflowNodeBase):
on_delete=models.CASCADE,
)
def get_absolute_url(self):
return reverse('api:workflow_job_template_node_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:workflow_job_template_node_detail', kwargs={'pk': self.pk}, request=request)
def create_wfjt_node_copy(self, user, workflow_job_template=None):
'''
@ -223,8 +223,8 @@ class WorkflowJobNode(WorkflowNodeBase):
editable=False,
)
def get_absolute_url(self):
return reverse('api:workflow_job_node_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:workflow_job_node_detail', kwargs={'pk': self.pk}, request=request)
def get_job_kwargs(self):
'''
@ -365,8 +365,8 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
return (base_list +
['survey_spec', 'survey_enabled', 'organization'])
def get_absolute_url(self):
return reverse('api:workflow_job_template_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:workflow_job_template_detail', kwargs={'pk': self.pk}, request=request)
@property
def cache_timeout_blocked(self):
@ -467,8 +467,8 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificatio
def socketio_emit_data(self):
return {}
def get_absolute_url(self):
return reverse('api:workflow_job_detail', args=(self.pk,))
def get_absolute_url(self, request=None):
return reverse('api:workflow_job_detail', kwargs={'pk': self.pk}, request=request)
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, '/#/workflows/{}'.format(self.pk))

View File

@ -1,12 +1,11 @@
import mock
import pytest
from awx.api.versioning import reverse
from awx.main.middleware import ActivityStreamMiddleware
from awx.main.models.activity_stream import ActivityStream
from awx.main.access import ActivityStreamAccess
from django.core.urlresolvers import reverse
def mock_feature_enabled(feature):
return True
@ -37,7 +36,7 @@ def test_basic_fields(monkeypatch, organization, get, user, settings):
activity_stream.save()
aspk = activity_stream.pk
url = reverse('api:activity_stream_detail', args=(aspk,))
url = reverse('api:activity_stream_detail', kwargs={'pk': aspk})
response = get(url, user('admin', True))
assert response.status_code == 200
@ -64,7 +63,7 @@ def test_middleware_actor_added(monkeypatch, post, get, user, settings):
org_id = response.data['id']
activity_stream = ActivityStream.objects.filter(organization__pk=org_id).first()
url = reverse('api:activity_stream_detail', args=(activity_stream.pk,))
url = reverse('api:activity_stream_detail', kwargs={'pk': activity_stream.pk})
response = get(url, u)
assert response.status_code == 200
@ -147,14 +146,14 @@ def test_stream_user_direct_role_updates(get, post, organization_factory):
users=['test'],
inventories=['inv1'])
url = reverse('api:user_roles_list', args=(objects.users.test.pk,))
url = reverse('api:user_roles_list', kwargs={'pk': objects.users.test.pk})
post(url, dict(id=objects.inventories.inv1.read_role.pk), objects.superusers.admin)
activity_stream = ActivityStream.objects.filter(
inventory__pk=objects.inventories.inv1.pk,
user__pk=objects.users.test.pk,
role__pk=objects.inventories.inv1.read_role.pk).first()
url = reverse('api:activity_stream_detail', args=(activity_stream.pk,))
url = reverse('api:activity_stream_detail', kwargs={'pk': activity_stream.pk})
response = get(url, objects.users.test)
assert response.data['object1'] == 'user'

View File

@ -1,7 +1,7 @@
import mock # noqa
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
"""
@ -108,8 +108,8 @@ def test_user_post_ad_hoc_command_list_without_inventory(alice, post_adhoc, inve
@pytest.mark.django_db
def test_admin_post_inventory_ad_hoc_command_list(admin, post_adhoc, inventory):
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', args=(inventory.id,)), {'inventory': None}, admin, expect=201)
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', args=(inventory.id,)), {}, admin, expect=201)
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inventory.id}), {'inventory': None}, admin, expect=201)
post_adhoc(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inventory.id}), {}, admin, expect=201)
@pytest.mark.django_db
@ -121,19 +121,19 @@ def test_get_inventory_ad_hoc_command_list(admin, alice, post_adhoc, get, invent
post_adhoc(reverse('api:ad_hoc_command_list'), {'inventory': inv2.id}, admin, expect=201)
res = get(reverse('api:ad_hoc_command_list'), admin, expect=200)
assert res.data['count'] == 2
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), admin, expect=200)
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), admin, expect=200)
assert res.data['count'] == 1
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv2.id,)), admin, expect=200)
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv2.id}), admin, expect=200)
assert res.data['count'] == 1
inv1.adhoc_role.members.add(alice)
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), alice, expect=200)
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), alice, expect=200)
assert res.data['count'] == 1
machine_credential.use_role.members.add(alice)
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv1.id,)), alice, expect=200)
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv1.id}), alice, expect=200)
assert res.data['count'] == 1
res = get(reverse('api:inventory_ad_hoc_commands_list', args=(inv2.id,)), alice, expect=403)
res = get(reverse('api:inventory_ad_hoc_commands_list', kwargs={'pk': inv2.id}), alice, expect=403)
@pytest.mark.django_db

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.mark.django_db
@ -10,7 +10,7 @@ def test_user_role_view_access(rando, inventory, mocker, post):
data = {"id": role_pk}
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
post(url=reverse('api:user_roles_list', args=(rando.pk,)),
post(url=reverse('api:user_roles_list', kwargs={'pk': rando.pk}),
data=data, user=rando, expect=403)
mock_access.can_attach.assert_called_once_with(
inventory.admin_role, rando, 'members', data,
@ -25,7 +25,7 @@ def test_team_role_view_access(rando, team, inventory, mocker, post):
data = {"id": role_pk}
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
post(url=reverse('api:team_roles_list', args=(team.pk,)),
post(url=reverse('api:team_roles_list', kwargs={'pk': team.pk}),
data=data, user=rando, expect=403)
mock_access.can_attach.assert_called_once_with(
inventory.admin_role, team, 'member_role.parents', data,
@ -40,7 +40,7 @@ def test_role_team_view_access(rando, team, inventory, mocker, post):
data = {"id": team.pk}
mock_access = mocker.MagicMock(return_value=False, __name__='mocked')
with mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access):
post(url=reverse('api:role_teams_list', args=(role_pk,)),
post(url=reverse('api:role_teams_list', kwargs={'pk': role_pk}),
data=data, user=rando, expect=403)
mock_access.assert_called_once_with(
inventory.admin_role, team, 'member_role.parents', data,
@ -54,7 +54,7 @@ def test_org_associate_with_junk_data(rando, admin_user, organization, post):
will turn off if the action is an association
"""
user_data = {'is_system_auditor': True, 'id': rando.pk}
post(url=reverse('api:organization_users_list', args=(organization.pk,)),
post(url=reverse('api:organization_users_list', kwargs={'pk': organization.pk}),
data=user_data, expect=204, user=admin_user)
# assure user is now an org member
assert rando in organization.member_role

View File

@ -1,7 +1,7 @@
import mock # noqa
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
#
@ -36,14 +36,14 @@ def test_credential_validation_error_with_bad_user(post, admin):
@pytest.mark.django_db
def test_create_user_credential_via_user_credentials_list(post, get, alice):
response = post(reverse('api:user_credentials_list', args=(alice.pk,)), {
response = post(reverse('api:user_credentials_list', kwargs={'pk': alice.pk}), {
'user': alice.pk,
'name': 'Some name',
'username': 'someusername',
}, alice)
assert response.status_code == 201
response = get(reverse('api:user_credentials_list', args=(alice.pk,)), alice)
response = get(reverse('api:user_credentials_list', kwargs={'pk': alice.pk}), alice)
assert response.status_code == 200
assert response.data['count'] == 1
@ -60,7 +60,7 @@ def test_create_user_credential_via_credentials_list_xfail(post, alice, bob):
@pytest.mark.django_db
def test_create_user_credential_via_user_credentials_list_xfail(post, alice, bob):
response = post(reverse('api:user_credentials_list', args=(bob.pk,)), {
response = post(reverse('api:user_credentials_list', kwargs={'pk': bob.pk}), {
'user': bob.pk,
'name': 'Some name',
'username': 'someusername'
@ -82,7 +82,7 @@ def test_create_team_credential(post, get, team, organization, org_admin, team_m
}, org_admin)
assert response.status_code == 201
response = get(reverse('api:team_credentials_list', args=(team.pk,)), team_member)
response = get(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), team_member)
assert response.status_code == 200
assert response.data['count'] == 1
@ -92,14 +92,14 @@ def test_create_team_credential(post, get, team, organization, org_admin, team_m
@pytest.mark.django_db
def test_create_team_credential_via_team_credentials_list(post, get, team, org_admin, team_member):
response = post(reverse('api:team_credentials_list', args=(team.pk,)), {
response = post(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), {
'team': team.pk,
'name': 'Some name',
'username': 'someusername',
}, org_admin)
assert response.status_code == 201
response = get(reverse('api:team_credentials_list', args=(team.pk,)), team_member)
response = get(reverse('api:team_credentials_list', kwargs={'pk': team.pk}), team_member)
assert response.status_code == 200
assert response.data['count'] == 1
@ -136,7 +136,7 @@ def test_create_team_credential_by_team_member_xfail(post, team, organization, a
def test_grant_org_credential_to_org_user_through_role_users(post, credential, organization, org_admin, org_member):
credential.organization = organization
credential.save()
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
'id': org_member.id
}, org_admin)
assert response.status_code == 204
@ -146,7 +146,7 @@ def test_grant_org_credential_to_org_user_through_role_users(post, credential, o
def test_grant_org_credential_to_org_user_through_user_roles(post, credential, organization, org_admin, org_member):
credential.organization = organization
credential.save()
response = post(reverse('api:user_roles_list', args=(org_member.id,)), {
response = post(reverse('api:user_roles_list', kwargs={'pk': org_member.id}), {
'id': credential.use_role.id
}, org_admin)
assert response.status_code == 204
@ -156,7 +156,7 @@ def test_grant_org_credential_to_org_user_through_user_roles(post, credential, o
def test_grant_org_credential_to_non_org_user_through_role_users(post, credential, organization, org_admin, alice):
credential.organization = organization
credential.save()
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
'id': alice.id
}, org_admin)
assert response.status_code == 400
@ -166,7 +166,7 @@ def test_grant_org_credential_to_non_org_user_through_role_users(post, credentia
def test_grant_org_credential_to_non_org_user_through_user_roles(post, credential, organization, org_admin, alice):
credential.organization = organization
credential.save()
response = post(reverse('api:user_roles_list', args=(alice.id,)), {
response = post(reverse('api:user_roles_list', kwargs={'pk': alice.id}), {
'id': credential.use_role.id
}, org_admin)
assert response.status_code == 400
@ -176,7 +176,7 @@ def test_grant_org_credential_to_non_org_user_through_user_roles(post, credentia
def test_grant_private_credential_to_user_through_role_users(post, credential, alice, bob):
# normal users can't do this
credential.admin_role.members.add(alice)
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
'id': bob.id
}, alice)
assert response.status_code == 400
@ -186,7 +186,7 @@ def test_grant_private_credential_to_user_through_role_users(post, credential, a
def test_grant_private_credential_to_org_user_through_role_users(post, credential, org_admin, org_member):
# org admins can't either
credential.admin_role.members.add(org_admin)
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
'id': org_member.id
}, org_admin)
assert response.status_code == 400
@ -195,7 +195,7 @@ def test_grant_private_credential_to_org_user_through_role_users(post, credentia
@pytest.mark.django_db
def test_sa_grant_private_credential_to_user_through_role_users(post, credential, admin, bob):
# but system admins can
response = post(reverse('api:role_users_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_users_list', kwargs={'pk': credential.use_role.id}), {
'id': bob.id
}, admin)
assert response.status_code == 204
@ -205,7 +205,7 @@ def test_sa_grant_private_credential_to_user_through_role_users(post, credential
def test_grant_private_credential_to_user_through_user_roles(post, credential, alice, bob):
# normal users can't do this
credential.admin_role.members.add(alice)
response = post(reverse('api:user_roles_list', args=(bob.id,)), {
response = post(reverse('api:user_roles_list', kwargs={'pk': bob.id}), {
'id': credential.use_role.id
}, alice)
assert response.status_code == 400
@ -215,7 +215,7 @@ def test_grant_private_credential_to_user_through_user_roles(post, credential, a
def test_grant_private_credential_to_org_user_through_user_roles(post, credential, org_admin, org_member):
# org admins can't either
credential.admin_role.members.add(org_admin)
response = post(reverse('api:user_roles_list', args=(org_member.id,)), {
response = post(reverse('api:user_roles_list', kwargs={'pk': org_member.id}), {
'id': credential.use_role.id
}, org_admin)
assert response.status_code == 400
@ -224,7 +224,7 @@ def test_grant_private_credential_to_org_user_through_user_roles(post, credentia
@pytest.mark.django_db
def test_sa_grant_private_credential_to_user_through_user_roles(post, credential, admin, bob):
# but system admins can
response = post(reverse('api:user_roles_list', args=(bob.id,)), {
response = post(reverse('api:user_roles_list', kwargs={'pk': bob.id}), {
'id': credential.use_role.id
}, admin)
assert response.status_code == 204
@ -235,7 +235,7 @@ def test_grant_org_credential_to_team_through_role_teams(post, credential, organ
assert org_auditor not in credential.read_role
credential.organization = organization
credential.save()
response = post(reverse('api:role_teams_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {
'id': team.id
}, org_admin)
assert response.status_code == 204
@ -247,7 +247,7 @@ def test_grant_org_credential_to_team_through_team_roles(post, credential, organ
assert org_auditor not in credential.read_role
credential.organization = organization
credential.save()
response = post(reverse('api:team_roles_list', args=(team.id,)), {
response = post(reverse('api:team_roles_list', kwargs={'pk': team.id}), {
'id': credential.use_role.id
}, org_admin)
assert response.status_code == 204
@ -257,7 +257,7 @@ def test_grant_org_credential_to_team_through_team_roles(post, credential, organ
@pytest.mark.django_db
def test_sa_grant_private_credential_to_team_through_role_teams(post, credential, admin, team):
# not even a system admin can grant a private cred to a team though
response = post(reverse('api:role_teams_list', args=(credential.use_role.id,)), {
response = post(reverse('api:role_teams_list', kwargs={'pk': credential.use_role.id}), {
'id': team.id
}, admin)
assert response.status_code == 400
@ -266,7 +266,7 @@ def test_sa_grant_private_credential_to_team_through_role_teams(post, credential
@pytest.mark.django_db
def test_sa_grant_private_credential_to_team_through_team_roles(post, credential, admin, team):
# not even a system admin can grant a private cred to a team though
response = post(reverse('api:role_teams_list', args=(team.id,)), {
response = post(reverse('api:role_teams_list', kwargs={'pk': team.id}), {
'id': credential.use_role.id
}, admin)
assert response.status_code == 400
@ -305,7 +305,7 @@ def test_credential_detail(post, get, organization, org_admin):
'organization': organization.id,
}, org_admin)
assert response.status_code == 201
response = get(reverse('api:credential_detail', args=(response.data['id'],)), org_admin)
response = get(reverse('api:credential_detail', kwargs={'pk': response.data['id']}), org_admin)
assert response.status_code == 200
summary_fields = response.data['summary_fields']
assert 'organization' in summary_fields
@ -330,11 +330,11 @@ def test_list_created_org_credentials(post, get, organization, org_admin, org_me
assert response.status_code == 200
assert response.data['count'] == 0
response = get(reverse('api:organization_credential_list', args=(organization.pk,)), org_admin)
response = get(reverse('api:organization_credential_list', kwargs={'pk': organization.pk}), org_admin)
assert response.status_code == 200
assert response.data['count'] == 1
response = get(reverse('api:organization_credential_list', args=(organization.pk,)), org_member)
response = get(reverse('api:organization_credential_list', kwargs={'pk': organization.pk}), org_member)
assert response.status_code == 200
assert response.data['count'] == 0

View File

@ -6,11 +6,11 @@ import urlparse
import urllib
# AWX
from awx.api.versioning import reverse
from awx.main.models.fact import Fact
from awx.main.utils import timestamp_apiformat
# Django
from django.core.urlresolvers import reverse
from django.utils import timezone
@ -26,7 +26,7 @@ def setup_common(hosts, fact_scans, get, user, epoch=timezone.now(), get_params=
hosts = hosts(host_count=host_count)
fact_scans(fact_scans=3, timestamp_epoch=epoch)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True), data=get_params)
return (hosts[0], response)
@ -37,7 +37,7 @@ def check_url(url1_full, fact_known, module):
url1 = url1_split.path
url1_params = urlparse.parse_qsl(url1_split.query)
url2 = reverse('api:host_fact_compare_view', args=(fact_known.host.pk,))
url2 = reverse('api:host_fact_compare_view', kwargs={'pk': fact_known.host.pk})
url2_params = [('module', module), ('datetime', timestamp_apiformat(fact_known.timestamp))]
assert url1 == url2
@ -64,7 +64,7 @@ def check_system_tracking_feature_forbidden(response):
@pytest.mark.license_feature
def test_system_tracking_license_get(hosts, get, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
check_system_tracking_feature_forbidden(response)
@ -75,7 +75,7 @@ def test_system_tracking_license_get(hosts, get, user):
@pytest.mark.license_feature
def test_system_tracking_license_options(hosts, options, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = options(url, None, user('admin', True))
check_system_tracking_feature_forbidden(response)
@ -86,7 +86,7 @@ def test_system_tracking_license_options(hosts, options, user):
@pytest.mark.license_feature
def test_no_facts_db(hosts, get, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
response_expected = {
@ -119,7 +119,7 @@ def test_basic_options_fields(hosts, fact_scans, options, user, monkeypatch_json
hosts = hosts(host_count=1)
fact_scans(fact_scans=1)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = options(url, None, user('admin', True), pk=hosts[0].id)
assert 'related' in response.data['actions']['GET']
@ -228,7 +228,7 @@ def _test_user_access_control(hosts, fact_scans, get, user_obj, team_obj):
team_obj.member_role.members.add(user_obj)
url = reverse('api:host_fact_versions_list', args=(hosts[0].pk,))
url = reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk})
response = get(url, user_obj)
return response

View File

@ -2,8 +2,8 @@ import mock
import pytest
import json
from awx.api.versioning import reverse
from awx.main.utils import timestamp_apiformat
from django.core.urlresolvers import reverse
from django.utils import timezone
@ -27,7 +27,7 @@ def setup_common(hosts, fact_scans, get, user, epoch=timezone.now(), module_name
hosts = hosts(host_count=1)
facts = fact_scans(fact_scans=1, timestamp_epoch=epoch)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True), data=get_params)
fact_known = find_fact(facts, hosts[0].id, module_name, epoch)
@ -44,7 +44,7 @@ def check_system_tracking_feature_forbidden(response):
@pytest.mark.license_feature
def test_system_tracking_license_get(hosts, get, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
check_system_tracking_feature_forbidden(response)
@ -55,7 +55,7 @@ def test_system_tracking_license_get(hosts, get, user):
@pytest.mark.license_feature
def test_system_tracking_license_options(hosts, options, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = options(url, None, user('admin', True))
check_system_tracking_feature_forbidden(response)
@ -65,7 +65,7 @@ def test_system_tracking_license_options(hosts, options, user):
@pytest.mark.django_db
def test_no_fact_found(hosts, get, user):
hosts = hosts(host_count=1)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
expected_response = {
@ -81,7 +81,7 @@ def test_basic_fields(hosts, fact_scans, get, user, monkeypatch_jsonbfield_get_d
hosts = hosts(host_count=1)
fact_scans(fact_scans=1)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
assert 'related' in response.data
@ -95,7 +95,7 @@ def test_basic_fields(hosts, fact_scans, get, user, monkeypatch_jsonbfield_get_d
assert 'name' in response.data['summary_fields']['host']
assert 'description' in response.data['summary_fields']['host']
assert 'host' in response.data['related']
assert reverse('api:host_detail', args=(hosts[0].pk,)) == response.data['related']['host']
assert reverse('api:host_detail', kwargs={'pk': hosts[0].pk}) == response.data['related']['host']
@mock.patch('awx.api.views.feature_enabled', new=mock_feature_enabled)
@ -149,7 +149,7 @@ def _test_user_access_control(hosts, fact_scans, get, user_obj, team_obj):
team_obj.member_role.members.add(user_obj)
url = reverse('api:host_fact_compare_view', args=(hosts[0].pk,))
url = reverse('api:host_fact_compare_view', kwargs={'pk': hosts[0].pk})
response = get(url, user_obj)
return response

View File

@ -2,17 +2,17 @@
# Other host tests should live here to make this test suite more complete.
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.mark.django_db
def test_basic_fields(hosts, fact_scans, get, user):
hosts = hosts(host_count=1)
url = reverse('api:host_detail', args=(hosts[0].pk,))
url = reverse('api:host_detail', kwargs={'pk': hosts[0].pk})
response = get(url, user('admin', True))
assert 'related' in response.data
assert 'fact_versions' in response.data['related']
assert reverse('api:host_fact_versions_list', args=(hosts[0].pk,)) == response.data['related']['fact_versions']
assert reverse('api:host_fact_versions_list', kwargs={'pk': hosts[0].pk}) == response.data['related']['fact_versions']

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.mark.django_db
@ -12,10 +12,10 @@ def test_inventory_source_notification_on_cloud_only(get, post, group_factory, u
not_is = g_not.inventory_source
cloud_is.source = 'ec2'
cloud_is.save()
url = reverse('api:inventory_source_notification_templates_any_list', args=(cloud_is.id,))
url = reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': cloud_is.id})
response = post(url, dict(id=notification_template.id), u)
assert response.status_code == 204
url = reverse('api:inventory_source_notification_templates_success_list', args=(not_is.id,))
url = reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': not_is.id})
response = post(url, dict(id=notification_template.id), u)
assert response.status_code == 400
@ -32,7 +32,7 @@ def test_edit_inventory(put, inventory, alice, role_field, expected_status_code)
data = { 'organization': inventory.organization.id, 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(inventory, role_field).members.add(alice)
put(reverse('api:inventory_detail', args=(inventory.id,)), data, alice, expect=expected_status_code)
put(reverse('api:inventory_detail', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize('order_by', ('script', '-script', 'script,pk', '-script,pk'))
@ -62,7 +62,7 @@ def test_create_inventory_group(post, inventory, alice, role_field, expected_sta
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(inventory, role_field).members.add(alice)
post(reverse('api:inventory_groups_list', args=(inventory.id,)), data, alice, expect=expected_status_code)
post(reverse('api:inventory_groups_list', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -77,7 +77,7 @@ def test_create_inventory_group_child(post, group, alice, role_field, expected_s
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(group.inventory, role_field).members.add(alice)
post(reverse('api:group_children_list', args=(group.id,)), data, alice, expect=expected_status_code)
post(reverse('api:group_children_list', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -92,7 +92,7 @@ def test_edit_inventory_group(put, group, alice, role_field, expected_status_cod
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(group.inventory, role_field).members.add(alice)
put(reverse('api:group_detail', args=(group.id,)), data, alice, expect=expected_status_code)
put(reverse('api:group_detail', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -106,7 +106,7 @@ def test_edit_inventory_group(put, group, alice, role_field, expected_status_cod
def test_delete_inventory_group(delete, group, alice, role_field, expected_status_code):
if role_field:
getattr(group.inventory, role_field).members.add(alice)
delete(reverse('api:group_detail', args=(group.id,)), alice, expect=expected_status_code)
delete(reverse('api:group_detail', kwargs={'pk': group.id}), alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -121,7 +121,7 @@ def test_create_inventory_host(post, inventory, alice, role_field, expected_stat
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(inventory, role_field).members.add(alice)
post(reverse('api:inventory_hosts_list', args=(inventory.id,)), data, alice, expect=expected_status_code)
post(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -136,7 +136,7 @@ def test_create_inventory_group_host(post, group, alice, role_field, expected_st
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(group.inventory, role_field).members.add(alice)
post(reverse('api:group_hosts_list', args=(group.id,)), data, alice, expect=expected_status_code)
post(reverse('api:group_hosts_list', kwargs={'pk': group.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -151,7 +151,7 @@ def test_edit_inventory_host(put, host, alice, role_field, expected_status_code)
data = { 'name': 'New name', 'description': 'Hello world', }
if role_field:
getattr(host.inventory, role_field).members.add(alice)
put(reverse('api:host_detail', args=(host.id,)), data, alice, expect=expected_status_code)
put(reverse('api:host_detail', kwargs={'pk': host.id}), data, alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -165,7 +165,7 @@ def test_edit_inventory_host(put, host, alice, role_field, expected_status_code)
def test_delete_inventory_host(delete, host, alice, role_field, expected_status_code):
if role_field:
getattr(host.inventory, role_field).members.add(alice)
delete(reverse('api:host_detail', args=(host.id,)), alice, expect=expected_status_code)
delete(reverse('api:host_detail', kwargs={'pk': host.id}), alice, expect=expected_status_code)
@pytest.mark.parametrize("role_field,expected_status_code", [
@ -179,4 +179,4 @@ def test_delete_inventory_host(delete, host, alice, role_field, expected_status_
def test_inventory_source_update(post, inventory_source, alice, role_field, expected_status_code):
if role_field:
getattr(inventory_source.group.inventory, role_field).members.add(alice)
post(reverse('api:inventory_source_update_view', args=(inventory_source.id,)), {}, alice, expect=expected_status_code)
post(reverse('api:inventory_source_update_view', kwargs={'pk': inventory_source.id}), {}, alice, expect=expected_status_code)

View File

@ -6,7 +6,7 @@ from awx.main.models.credential import Credential
from awx.main.models.inventory import Inventory
from awx.main.models.jobs import Job, JobTemplate
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.fixture
@ -85,7 +85,7 @@ def test_job_ignore_unprompted_vars(runtime_data, job_template_prompts, post, ad
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
runtime_data, admin_user, expect=201)
assert JobTemplate.create_unified_job.called
assert JobTemplate.create_unified_job.call_args == ({'extra_vars':{}},)
@ -116,7 +116,7 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, admi
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
runtime_data, admin_user, expect=201)
assert JobTemplate.create_unified_job.called
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
@ -136,7 +136,7 @@ def test_job_accept_null_tags(job_template_prompts, post, admin_user, mocker):
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
post(reverse('api:job_template_launch', args=[job_template.pk]),
post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}),
{'job_tags': '', 'skip_tags': ''}, admin_user, expect=201)
assert JobTemplate.create_unified_job.called
assert JobTemplate.create_unified_job.call_args == ({'job_tags':'', 'skip_tags':''},)
@ -162,7 +162,7 @@ def test_job_accept_prompted_vars_null(runtime_data, job_template_prompts_null,
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
with mocker.patch('awx.api.serializers.JobSerializer.to_representation'):
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk': job_template.pk}),
runtime_data, rando, expect=201)
assert JobTemplate.create_unified_job.called
assert JobTemplate.create_unified_job.call_args == (runtime_data,)
@ -178,7 +178,7 @@ def test_job_reject_invalid_prompted_vars(runtime_data, job_template_prompts, po
job_template = job_template_prompts(True)
response = post(
reverse('api:job_template_launch', args=[job_template.pk]),
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(job_type='foobicate', # foobicate is not a valid job type
inventory=87865, credential=48474), admin_user, expect=400)
@ -193,7 +193,7 @@ def test_job_reject_invalid_prompted_extra_vars(runtime_data, job_template_promp
job_template = job_template_prompts(True)
response = post(
reverse('api:job_template_launch', args=[job_template.pk]),
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(extra_vars='{"unbalanced brackets":'), admin_user, expect=400)
assert 'extra_vars' in response.data
@ -207,7 +207,7 @@ def test_job_launch_fails_without_inventory(deploy_jobtemplate, post, admin_user
deploy_jobtemplate.save()
response = post(reverse('api:job_template_launch',
args=[deploy_jobtemplate.pk]), {}, admin_user, expect=400)
kwargs={'pk': deploy_jobtemplate.pk}), {}, admin_user, expect=400)
assert response.data['inventory'] == ["Job Template 'inventory' is missing or undefined."]
@ -219,7 +219,7 @@ def test_job_launch_fails_without_inventory_access(job_template_prompts, runtime
job_template.execute_role.members.add(rando)
# Assure that giving an inventory without access to the inventory blocks the launch
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(inventory=runtime_data['inventory']), rando, expect=403)
assert response.data['detail'] == u'You do not have permission to perform this action.'
@ -232,7 +232,7 @@ def test_job_launch_fails_without_credential_access(job_template_prompts, runtim
job_template.execute_role.members.add(rando)
# Assure that giving a credential without access blocks the launch
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(credential=runtime_data['credential']), rando, expect=403)
assert response.data['detail'] == u'You do not have permission to perform this action.'
@ -244,7 +244,7 @@ def test_job_block_scan_job_type_change(job_template_prompts, post, admin_user):
job_template = job_template_prompts(True)
# Assure that changing the type of a scan job blocks the launch
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(job_type='scan'), admin_user, expect=400)
assert 'job_type' in response.data
@ -255,7 +255,7 @@ def test_job_block_scan_job_type_change(job_template_prompts, post, admin_user):
def test_job_block_scan_job_inv_change(mocker, bad_scan_JT, runtime_data, post, admin_user):
# Assure that giving a new inventory for a scan job blocks the launch
with mocker.patch('awx.main.access.BaseAccess.check_license'):
response = post(reverse('api:job_template_launch', args=[bad_scan_JT.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk': bad_scan_JT.pk}),
dict(inventory=runtime_data['inventory']), admin_user,
expect=400)
@ -333,7 +333,7 @@ def test_job_launch_unprompted_vars_with_survey(mocker, survey_spec_factory, job
with mocker.patch.object(JobTemplate, 'create_unified_job', return_value=mock_job):
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
response = post(
reverse('api:job_template_launch', args=[job_template.pk]),
reverse('api:job_template_launch', kwargs={'pk':job_template.pk}),
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}),
admin_user, expect=201)
assert JobTemplate.create_unified_job.called
@ -362,7 +362,7 @@ def test_callback_accept_prompted_extra_var(mocker, survey_spec_factory, job_tem
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
post(
reverse('api:job_template_callback', args=[job_template.pk]),
reverse('api:job_template_callback', kwargs={'pk': job_template.pk}),
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
admin_user, expect=201, format='json')
assert JobTemplate.create_unified_job.called
@ -387,7 +387,7 @@ def test_callback_ignore_unprompted_extra_var(mocker, survey_spec_factory, job_t
with mocker.patch('awx.api.serializers.JobSerializer.to_representation', return_value={}):
with mocker.patch('awx.api.views.JobTemplateCallback.find_matching_hosts', return_value=[host]):
post(
reverse('api:job_template_callback', args=[job_template.pk]),
reverse('api:job_template_callback', kwargs={'pk':job_template.pk}),
dict(extra_vars={"job_launch_var": 3, "survey_var": 4}, host_config_key="foo"),
admin_user, expect=201, format='json')
assert JobTemplate.create_unified_job.called

View File

@ -2,11 +2,11 @@ import pytest
# AWX
from awx.api.serializers import JobTemplateSerializer, JobLaunchSerializer
from awx.api.versioning import reverse
from awx.main.models.jobs import Job
from awx.main.migrations import _save_password_keys as save_password_keys
# Django
from django.core.urlresolvers import reverse
from django.apps import apps
@ -56,7 +56,7 @@ def test_edit_sensitive_fields(patch, job_template_factory, alice, grant_project
if grant_inventory:
objs.inventory.use_role.members.add(alice)
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
'name': 'Some name',
'project': objs.project.id,
'credential': objs.credential.id,
@ -72,7 +72,7 @@ def test_reject_dict_extra_vars_patch(patch, job_template_factory, admin_user):
jt = job_template_factory(
'jt', organization='org1', project='prj', inventory='inv', credential='cred'
).job_template
patch(reverse('api:job_template_detail', args=(jt.id,)),
patch(reverse('api:job_template_detail', kwargs={'pk': jt.id}),
{'extra_vars': {'foo': 5}}, admin_user, expect=400)
@ -84,12 +84,12 @@ def test_edit_playbook(patch, job_template_factory, alice):
objs.credential.use_role.members.add(alice)
objs.inventory.use_role.members.add(alice)
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
'playbook': 'alt-helloworld.yml',
}, alice, expect=200)
objs.inventory.use_role.members.remove(alice)
patch(reverse('api:job_template_detail', args=(objs.job_template.id,)), {
patch(reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}), {
'playbook': 'helloworld.yml',
}, alice, expect=403)
@ -101,7 +101,7 @@ def test_invalid_json_body(patch, job_template_factory, alice, json_body):
objs = job_template_factory('jt', organization='org1')
objs.job_template.admin_role.members.add(alice)
resp = patch(
reverse('api:job_template_detail', args=(objs.job_template.id,)),
reverse('api:job_template_detail', kwargs={'pk': objs.job_template.id}),
json_body,
alice,
expect=400
@ -117,7 +117,7 @@ def test_edit_nonsenstive(patch, job_template_factory, alice):
jt = objs.job_template
jt.admin_role.members.add(alice)
res = patch(reverse('api:job_template_detail', args=(jt.id,)), {
res = patch(reverse('api:job_template_detail', kwargs={'pk': jt.id}), {
'name': 'updated',
'description': 'bar',
'forks': 14,
@ -157,7 +157,7 @@ def test_job_template_role_user(post, organization_factory, job_template_factory
inventory='test_inv',
project='test_proj')
url = reverse('api:user_roles_list', args=(objects.users.test.pk,))
url = reverse('api:user_roles_list', kwargs={'pk': objects.users.test.pk})
response = post(url, dict(id=jt_objects.job_template.execute_role.pk), objects.superusers.admin)
assert response.status_code == 204
@ -168,12 +168,12 @@ def test_jt_admin_copy_edit_functional(jt_copy_edit, rando, get, post):
jt_copy_edit.admin_role.members.add(rando)
jt_copy_edit.save()
get_response = get(reverse('api:job_template_detail', args=[jt_copy_edit.pk]), user=rando)
get_response = get(reverse('api:job_template_detail', kwargs={'pk':jt_copy_edit.pk}), user=rando)
assert get_response.status_code == 200
post_data = get_response.data
post_data['name'] = '%s @ 12:19:47 pm' % post_data['name']
post_response = post(reverse('api:job_template_list', args=[]), user=rando, data=post_data)
post_response = post(reverse('api:job_template_list'), user=rando, data=post_data)
assert post_response.status_code == 403
@ -244,7 +244,7 @@ def test_disallow_template_delete_on_running_job(job_template_factory, delete, a
inventory='i',
organization='o')
objects.job_template.create_unified_job()
delete_response = delete(reverse('api:job_template_detail', args=[objects.job_template.pk]), user=admin_user)
delete_response = delete(reverse('api:job_template_detail', kwargs={'pk': objects.job_template.pk}), user=admin_user)
assert delete_response.status_code == 409

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.fixture
@ -70,7 +70,7 @@ def test_org_counts_detail_admin(resourced_organization, user, get):
# Check that all types of resources are counted by a superuser
external_admin = user('admin', True)
response = get(reverse('api:organization_detail',
args=[resourced_organization.pk]), external_admin)
kwargs={'pk': resourced_organization.pk}), external_admin)
assert response.status_code == 200
counts = response.data['summary_fields']['related_field_counts']
@ -82,7 +82,7 @@ def test_org_counts_detail_member(resourced_organization, user, get):
# Check that a non-admin org member can only see users / admin in detail view
member_user = resourced_organization.member_role.members.get(username='org-member 1')
response = get(reverse('api:organization_detail',
args=[resourced_organization.pk]), member_user)
kwargs={'pk': resourced_organization.pk}), member_user)
assert response.status_code == 200
counts = response.data['summary_fields']['related_field_counts']
@ -100,7 +100,7 @@ def test_org_counts_detail_member(resourced_organization, user, get):
def test_org_counts_list_admin(resourced_organization, user, get):
# Check that all types of resources are counted by a superuser
external_admin = user('admin', True)
response = get(reverse('api:organization_list', args=[]), external_admin)
response = get(reverse('api:organization_list'), external_admin)
assert response.status_code == 200
counts = response.data['results'][0]['summary_fields']['related_field_counts']
@ -112,7 +112,7 @@ def test_org_counts_list_member(resourced_organization, user, get):
# Check that a non-admin user can only see the full project and
# user count, consistent with the RBAC rules
member_user = resourced_organization.member_role.members.get(username='org-member 1')
response = get(reverse('api:organization_list', args=[]), member_user)
response = get(reverse('api:organization_list'), member_user)
assert response.status_code == 200
counts = response.data['results'][0]['summary_fields']['related_field_counts']
@ -131,7 +131,7 @@ def test_org_counts_list_member(resourced_organization, user, get):
def test_new_org_zero_counts(user, post):
# Check that a POST to the organization list endpoint returns
# correct counts, including the new record
org_list_url = reverse('api:organization_list', args=[])
org_list_url = reverse('api:organization_list')
post_response = post(url=org_list_url, data={'name': 'test organization',
'description': ''}, user=user('admin', True))
assert post_response.status_code == 201
@ -146,7 +146,7 @@ def test_two_organizations(resourced_organization, organizations, user, get):
# Check correct results for two organizations are returned
external_admin = user('admin', True)
organization_zero = organizations(1)[0]
response = get(reverse('api:organization_list', args=[]), external_admin)
response = get(reverse('api:organization_list'), external_admin)
assert response.status_code == 200
org_id_full = resourced_organization.id
@ -171,12 +171,12 @@ def test_scan_JT_counted(resourced_organization, user, get):
counts_dict['job_templates'] += 1
# Test list view
list_response = get(reverse('api:organization_list', args=[]), admin_user)
list_response = get(reverse('api:organization_list'), admin_user)
assert list_response.status_code == 200
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
# Test detail view
detail_response = get(reverse('api:organization_detail', args=[resourced_organization.pk]), admin_user)
detail_response = get(reverse('api:organization_detail', kwargs={'pk': resourced_organization.pk}), admin_user)
assert detail_response.status_code == 200
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
@ -194,12 +194,12 @@ def test_JT_not_double_counted(resourced_organization, user, get):
counts_dict['job_templates'] += 1
# Test list view
list_response = get(reverse('api:organization_list', args=[]), admin_user)
list_response = get(reverse('api:organization_list'), admin_user)
assert list_response.status_code == 200
assert list_response.data['results'][0]['summary_fields']['related_field_counts'] == counts_dict
# Test detail view
detail_response = get(reverse('api:organization_detail', args=[resourced_organization.pk]), admin_user)
detail_response = get(reverse('api:organization_detail', kwargs={'pk': resourced_organization.pk}), admin_user)
assert detail_response.status_code == 200
assert detail_response.data['summary_fields']['related_field_counts'] == counts_dict
@ -220,7 +220,7 @@ def test_JT_associated_with_project(organizations, project, user, get):
inventory=unrelated_inv,
playbook="test_playbook.yml")
response = get(reverse('api:organization_list', args=[]), external_admin)
response = get(reverse('api:organization_list'), external_admin)
assert response.status_code == 200
org_id = organization.id

View File

@ -7,7 +7,7 @@ import mock
# Django
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
# AWX
from awx.main.models import * # noqa
@ -29,10 +29,10 @@ def test_organization_list_access_tests(options, head, get, admin, alice):
@pytest.mark.django_db
def test_organization_access_tests(organization, get, admin, alice, bob):
organization.member_role.members.add(alice)
get(reverse('api:organization_detail', args=(organization.id,)), user=admin, expect=200)
get(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=200)
get(reverse('api:organization_detail', args=(organization.id,)), user=bob, expect=403)
get(reverse('api:organization_detail', args=(organization.id,)), user=None, expect=401)
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=admin, expect=200)
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=200)
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=bob, expect=403)
get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=None, expect=401)
@pytest.mark.django_db
@ -68,9 +68,9 @@ def test_organization_project_list(organization, project_factory, get, alice, bo
organization.admin_role.members.add(alice)
organization.member_role.members.add(bob)
prj1.use_role.members.add(bob)
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=alice).data['count'] == 2
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=bob).data['count'] == 1
assert get(reverse('api:organization_projects_list', args=(organization.id,)), user=rando).status_code == 403
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
assert get(reverse('api:organization_projects_list', kwargs={'pk': organization.id}), user=rando).status_code == 403
@pytest.mark.django_db
@ -78,12 +78,12 @@ def test_organization_user_list(organization, get, admin, alice, bob):
organization.admin_role.members.add(alice)
organization.member_role.members.add(alice)
organization.member_role.members.add(bob)
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=admin).data['count'] == 2
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=alice).data['count'] == 2
assert get(reverse('api:organization_users_list', args=(organization.id,)), user=bob).data['count'] == 2
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=admin).data['count'] == 1
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=alice).data['count'] == 1
assert get(reverse('api:organization_admins_list', args=(organization.id,)), user=bob).data['count'] == 1
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=admin).data['count'] == 2
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
assert get(reverse('api:organization_users_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 2
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=admin).data['count'] == 1
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 1
assert get(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
@pytest.mark.django_db
@ -93,9 +93,9 @@ def test_organization_inventory_list(organization, inventory_factory, get, alice
organization.admin_role.members.add(alice)
organization.member_role.members.add(bob)
inv1.use_role.members.add(bob)
assert get(reverse('api:organization_inventories_list', args=(organization.id,)), user=alice).data['count'] == 2
assert get(reverse('api:organization_inventories_list', args=(organization.id,)), user=bob).data['count'] == 1
get(reverse('api:organization_inventories_list', args=(organization.id,)), user=rando, expect=403)
assert get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=alice).data['count'] == 2
assert get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=bob).data['count'] == 1
get(reverse('api:organization_inventories_list', kwargs={'pk': organization.id}), user=rando, expect=403)
@pytest.mark.django_db
@ -123,25 +123,25 @@ def test_create_organization_xfail(post, alice):
@pytest.mark.django_db
def test_add_user_to_organization(post, organization, alice, bob):
organization.admin_role.members.add(alice)
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=204)
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=204)
assert bob in organization.member_role
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
assert bob not in organization.member_role
@pytest.mark.django_db
def test_add_user_to_organization_xfail(post, organization, alice, bob):
organization.member_role.members.add(alice)
post(reverse('api:organization_users_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=403)
post(reverse('api:organization_users_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=403)
@pytest.mark.django_db
def test_add_admin_to_organization(post, organization, alice, bob):
organization.admin_role.members.add(alice)
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=204)
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=204)
assert bob in organization.admin_role
assert bob in organization.member_role
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id, 'disassociate': True} , user=alice, expect=204)
assert bob not in organization.admin_role
assert bob not in organization.member_role
@ -149,42 +149,42 @@ def test_add_admin_to_organization(post, organization, alice, bob):
@pytest.mark.django_db
def test_add_admin_to_organization_xfail(post, organization, alice, bob):
organization.member_role.members.add(alice)
post(reverse('api:organization_admins_list', args=(organization.id,)), {'id': bob.id}, user=alice, expect=403)
post(reverse('api:organization_admins_list', kwargs={'pk': organization.id}), {'id': bob.id}, user=alice, expect=403)
@pytest.mark.django_db
def test_update_organization(get, put, organization, alice, bob):
organization.admin_role.members.add(alice)
data = get(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=200).data
data = get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=200).data
data['description'] = 'hi'
put(reverse('api:organization_detail', args=(organization.id,)), data, user=alice, expect=200)
put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=alice, expect=200)
organization.refresh_from_db()
assert organization.description == 'hi'
data['description'] = 'bye'
put(reverse('api:organization_detail', args=(organization.id,)), data, user=bob, expect=403)
put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=bob, expect=403)
@pytest.mark.django_db
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
def test_delete_organization(delete, organization, admin):
delete(reverse('api:organization_detail', args=(organization.id,)), user=admin, expect=204)
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=admin, expect=204)
@pytest.mark.django_db
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
def test_delete_organization2(delete, organization, alice):
organization.admin_role.members.add(alice)
delete(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=204)
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=204)
@pytest.mark.django_db
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
def test_delete_organization_xfail1(delete, organization, alice):
organization.member_role.members.add(alice)
delete(reverse('api:organization_detail', args=(organization.id,)), user=alice, expect=403)
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=403)
@pytest.mark.django_db
@mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True)
def test_delete_organization_xfail2(delete, organization):
delete(reverse('api:organization_detail', args=(organization.id,)), user=None, expect=401)
delete(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=None, expect=401)

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from django.test.client import RequestFactory
from awx.main.models import Role, Group, UnifiedJobTemplate, JobTemplate
@ -30,17 +30,17 @@ class TestOptionsRBAC:
def test_inventory_group_host_can_add(self, inventory, alice, options):
inventory.admin_role.members.add(alice)
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), alice)
response = options(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.pk}), alice)
assert 'POST' in response.data['actions']
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), alice)
response = options(reverse('api:inventory_groups_list', kwargs={'pk': inventory.pk}), alice)
assert 'POST' in response.data['actions']
def test_inventory_group_host_can_not_add(self, inventory, bob, options):
inventory.read_role.members.add(bob)
response = options(reverse('api:inventory_hosts_list', args=[inventory.pk]), bob)
response = options(reverse('api:inventory_hosts_list', kwargs={'pk': inventory.pk}), bob)
assert 'POST' not in response.data['actions']
response = options(reverse('api:inventory_groups_list', args=[inventory.pk]), bob)
response = options(reverse('api:inventory_groups_list', kwargs={'pk': inventory.pk}), bob)
assert 'POST' not in response.data['actions']
def test_user_list_can_add(self, org_member, org_admin, options):
@ -192,7 +192,7 @@ class TestAccessListCapabilities:
inventory.admin_role.members.add(rando)
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), rando)
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), rando)
mock_access_method.assert_called_once_with(inventory.admin_role, rando, 'members', **self.extra_kwargs)
self._assert_one_in_list(response.data)
@ -202,7 +202,7 @@ class TestAccessListCapabilities:
def test_access_list_indirect_access_capability(
self, inventory, organization, org_admin, get, mocker, mock_access_method):
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), org_admin)
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), org_admin)
mock_access_method.assert_called_once_with(organization.admin_role, org_admin, 'members', **self.extra_kwargs)
self._assert_one_in_list(response.data, sublist='indirect_access')
@ -214,7 +214,7 @@ class TestAccessListCapabilities:
team.member_role.children.add(inventory.admin_role)
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
response = get(reverse('api:inventory_access_list', args=(inventory.id,)), team_member)
response = get(reverse('api:inventory_access_list', kwargs={'pk': inventory.id}), team_member)
mock_access_method.assert_called_once_with(inventory.admin_role, team.member_role, 'parents', **self.extra_kwargs)
self._assert_one_in_list(response.data)
@ -223,7 +223,7 @@ class TestAccessListCapabilities:
def test_user_access_list_direct_access_capability(self, rando, get):
"When a user views their own access list, they cannot unattach their admin role"
response = get(reverse('api:user_access_list', args=(rando.id,)), rando)
response = get(reverse('api:user_access_list', kwargs={'pk': rando.id}), rando)
direct_access_list = response.data['results'][0]['summary_fields']['direct_access']
assert not direct_access_list[0]['role']['user_capabilities']['unattach']
@ -233,7 +233,7 @@ def test_team_roles_unattach(mocker, team, team_member, inventory, mock_access_m
team.member_role.children.add(inventory.admin_role)
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member)
# Did we assess whether team_member can remove team's permission to the inventory?
mock_access_method.assert_called_once_with(
@ -248,7 +248,7 @@ def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_metho
organization.member_role.members.add(bob)
with mocker.patch.object(access_registry[Role][0], 'can_unattach', mock_access_method):
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob)
# Did we assess whether bob can remove alice's permission to the inventory?
mock_access_method.assert_called_once_with(
@ -259,7 +259,7 @@ def test_user_roles_unattach(mocker, organization, alice, bob, mock_access_metho
@pytest.mark.django_db
def test_team_roles_unattach_functional(team, team_member, inventory, get):
team.member_role.children.add(inventory.admin_role)
response = get(reverse('api:team_roles_list', args=(team.id,)), team_member)
response = get(reverse('api:team_roles_list', kwargs={'pk': team.id}), team_member)
# Team member should be able to remove access to inventory, becauase
# the inventory admin_role grants that ability
assert response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
@ -269,7 +269,7 @@ def test_team_roles_unattach_functional(team, team_member, inventory, get):
def test_user_roles_unattach_functional(organization, alice, bob, get):
organization.member_role.members.add(alice)
organization.member_role.members.add(bob)
response = get(reverse('api:user_roles_list', args=(alice.id,)), bob)
response = get(reverse('api:user_roles_list', kwargs={'pk': alice.id}), bob)
# Org members cannot revoke the membership of other members
assert not response.data['results'][0]['summary_fields']['user_capabilities']['unattach']
@ -336,7 +336,7 @@ def test_prefetch_jt_copy_capability(job_template, project, inventory, machine_c
@pytest.mark.django_db
def test_manual_projects_no_update(project, get, admin_user):
response = get(reverse('api:project_detail', args=[project.pk]), admin_user, expect=200)
response = get(reverse('api:project_detail', kwargs={'pk': project.pk}), admin_user, expect=200)
assert not response.data['summary_fields']['user_capabilities']['start']
assert not response.data['summary_fields']['user_capabilities']['schedule']
@ -369,5 +369,5 @@ def test_license_check_not_called(mocker, job_template, project, org_admin, get)
job_template.save() # need this to make the JT visible
mock_license_check = mocker.MagicMock()
with mocker.patch('awx.main.access.BaseAccess.check_license', mock_license_check):
get(reverse('api:job_template_detail', args=[job_template.pk]), org_admin, expect=200)
get(reverse('api:job_template_detail', kwargs={'pk': job_template.pk}), org_admin, expect=200)
assert not mock_license_check.called

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from awx.main.models import Role
@ -19,7 +19,7 @@ def test_indirect_access_list(get, organization, project, team_factory, user, ad
project_admin_team.admin_role.members.add(team_admin)
result = get(reverse('api:project_access_list', args=(project.id,)), admin)
result = get(reverse('api:project_access_list', kwargs={'pk': project.id}), admin)
assert result.status_code == 200
# Result should be:

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.mark.django_db

View File

@ -9,10 +9,8 @@ import os
# Mock
import mock
# Django
from django.core.urlresolvers import reverse
# AWX
from awx.api.versioning import reverse
from awx.conf.models import Setting
from awx.main.utils.handlers import BaseHTTPSHandler, LoggingConnectivityException
@ -32,7 +30,7 @@ def mock_no_license_file(mocker):
@pytest.mark.django_db
def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get, put, patch, delete, admin, enterprise_license):
url = reverse('api:setting_singleton_detail', args=('system',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'})
response = get(url, user=admin, expect=200)
assert not response.data['LICENSE']
Setting.objects.create(key='TOWER_URL_BASE', value='https://towerhost')
@ -53,13 +51,13 @@ def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get
@pytest.mark.django_db
def test_url_base_defaults_to_request(options, admin):
# If TOWER_URL_BASE is not set, default to the Tower request hostname
resp = options(reverse('api:setting_singleton_detail', args=('system',)), user=admin, expect=200)
resp = options(reverse('api:setting_singleton_detail', kwargs={'category_slug': 'system'}), user=admin, expect=200)
assert resp.data['actions']['PUT']['TOWER_URL_BASE']['default'] == 'http://testserver'
@pytest.mark.django_db
def test_jobs_settings(get, put, patch, delete, admin):
url = reverse('api:setting_singleton_detail', args=('jobs',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'jobs'})
get(url, user=admin, expect=200)
delete(url, user=admin, expect=204)
response = get(url, user=admin, expect=200)
@ -80,7 +78,7 @@ def test_jobs_settings(get, put, patch, delete, admin):
@pytest.mark.django_db
def test_ldap_settings(get, put, patch, delete, admin, enterprise_license):
url = reverse('api:setting_singleton_detail', args=('ldap',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'})
get(url, user=admin, expect=404)
Setting.objects.create(key='LICENSE', value=enterprise_license)
get(url, user=admin, expect=200)
@ -107,7 +105,7 @@ def test_ldap_settings(get, put, patch, delete, admin, enterprise_license):
@pytest.mark.django_db
def test_empty_ldap_dn(get, put, patch, delete, admin, enterprise_license,
setting):
url = reverse('api:setting_singleton_detail', args=('ldap',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'})
Setting.objects.create(key='LICENSE', value=enterprise_license)
patch(url, user=admin, data={setting: ''}, expect=200)
@ -121,7 +119,7 @@ def test_empty_ldap_dn(get, put, patch, delete, admin, enterprise_license,
@pytest.mark.django_db
def test_radius_settings(get, put, patch, delete, admin, enterprise_license, settings):
url = reverse('api:setting_singleton_detail', args=('radius',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'radius'})
get(url, user=admin, expect=404)
Setting.objects.create(key='LICENSE', value=enterprise_license)
response = get(url, user=admin, expect=200)
@ -155,7 +153,7 @@ def test_radius_settings(get, put, patch, delete, admin, enterprise_license, set
@pytest.mark.django_db
def test_ui_settings(get, put, patch, delete, admin, enterprise_license):
url = reverse('api:setting_singleton_detail', args=('ui',))
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ui'})
response = get(url, user=admin, expect=200)
assert 'CUSTOM_LOGO' not in response.data
assert 'CUSTOM_LOGIN_INFO' not in response.data

View File

@ -2,8 +2,8 @@ import mock
import pytest
import json
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from awx.main.models.jobs import JobTemplate, Job
from awx.main.models.activity_stream import ActivityStream
from awx.conf.license import LicenseForbids
@ -30,7 +30,7 @@ def job_template_with_survey(job_template_factory):
def test_survey_spec_view_denied(job_template_with_survey, get, admin_user):
# TODO: Test non-enterprise license
response = get(reverse('api:job_template_survey_spec',
args=(job_template_with_survey.id,)), admin_user, expect=402)
kwargs={'pk': job_template_with_survey.id}), admin_user, expect=402)
assert response.data['detail'] == 'Your license does not allow adding surveys.'
@ -76,7 +76,7 @@ def test_deny_creating_with_survey(project, post, admin_user):
@pytest.mark.django_db
@pytest.mark.survey
def test_survey_spec_view_allowed(deploy_jobtemplate, get, admin_user):
get(reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
get(reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
admin_user, expect=200)
@ -85,7 +85,7 @@ def test_survey_spec_view_allowed(deploy_jobtemplate, get, admin_user):
@pytest.mark.survey
def test_survey_spec_sucessful_creation(survey_spec_factory, job_template, post, admin_user):
survey_input_data = survey_spec_factory('new_question')
post(url=reverse('api:job_template_survey_spec', args=(job_template.id,)),
post(url=reverse('api:job_template_survey_spec', kwargs={'pk': job_template.id}),
data=survey_input_data, user=admin_user, expect=200)
updated_jt = JobTemplate.objects.get(pk=job_template.pk)
assert updated_jt.survey_spec == survey_input_data
@ -98,10 +98,14 @@ def test_survey_spec_sucessful_creation(survey_spec_factory, job_template, post,
def test_survey_spec_non_dict_error(deploy_jobtemplate, post, admin_user):
"""When a question doesn't follow the standard format, verify error thrown."""
response = post(
url=reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
data={"description": "Email of the submitter",
"spec": ["What is your email?"], "name": "Email survey"},
user=admin_user, expect=400)
url=reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
data={
"description": "Email of the submitter",
"spec": ["What is your email?"], "name": "Email survey"
},
user=admin_user,
expect=400
)
assert response.data['error'] == "Survey question 0 is not a json object."
@ -110,9 +114,11 @@ def test_survey_spec_non_dict_error(deploy_jobtemplate, post, admin_user):
@pytest.mark.survey
def test_survey_spec_dual_names_error(survey_spec_factory, deploy_jobtemplate, post, user):
response = post(
url=reverse('api:job_template_survey_spec', args=(deploy_jobtemplate.id,)),
url=reverse('api:job_template_survey_spec', kwargs={'pk': deploy_jobtemplate.id}),
data=survey_spec_factory(['submitter_email', 'submitter_email']),
user=user('admin', True), expect=400)
user=user('admin', True),
expect=400
)
assert response.data['error'] == "'variable' 'submitter_email' duplicated in survey question 1."
@ -166,7 +172,7 @@ def test_job_template_delete_access_with_survey(job_template_with_survey, admin_
@pytest.mark.survey
def test_delete_survey_spec_without_license(job_template_with_survey, delete, admin_user):
"""Functional delete test through the survey_spec view."""
delete(reverse('api:job_template_survey_spec', args=[job_template_with_survey.pk]),
delete(reverse('api:job_template_survey_spec', kwargs={'pk': job_template_with_survey.pk}),
admin_user, expect=200)
new_jt = JobTemplate.objects.get(pk=job_template_with_survey.pk)
assert new_jt.survey_spec == {}
@ -185,7 +191,7 @@ def test_launch_survey_enabled_but_no_survey_spec(job_template_factory, post, ad
obj = objects.job_template
obj.survey_enabled = True
obj.save()
response = post(reverse('api:job_template_launch', args=[obj.pk]),
response = post(reverse('api:job_template_launch', kwargs={'pk':obj.pk}),
dict(extra_vars=dict(survey_var=7)), admin_user, expect=201)
assert 'survey_var' in response.data['ignored_fields']['extra_vars']
@ -205,7 +211,7 @@ def test_launch_with_non_empty_survey_spec_no_license(job_template_factory, post
obj = objects.job_template
obj.survey_enabled = False
obj.save()
post(reverse('api:job_template_launch', args=[obj.pk]), {}, admin_user, expect=201)
post(reverse('api:job_template_launch', kwargs={'pk': obj.pk}), {}, admin_user, expect=201)
@pytest.mark.django_db

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
@pytest.mark.django_db

View File

@ -1,7 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from awx.main.models import UnifiedJob, ProjectUpdate
from awx.main.tests.base import URI
@ -60,7 +59,7 @@ formats = [
def test_project_update_redaction_enabled(get, format, content_type, test_cases, admin):
for test_data in test_cases:
job = test_data['project']
response = get(reverse("api:project_update_stdout", args=(job.pk,)) + "?format=" + format, user=admin, expect=200, accept=content_type)
response = get(reverse("api:project_update_stdout", kwargs={'pk': job.pk}) + "?format=" + format, user=admin, expect=200, accept=content_type)
assert content_type in response['CONTENT-TYPE']
assert response.data is not None
content = response.data['content'] if format == 'json' else response.data
@ -74,7 +73,7 @@ def test_project_update_redaction_enabled(get, format, content_type, test_cases,
def test_job_redaction_disabled(get, format, content_type, negative_test_cases, admin):
for test_data in negative_test_cases:
job = test_data['job']
response = get(reverse("api:job_stdout", args=(job.pk,)) + "?format=" + format, user=admin, expect=200, format=format)
response = get(reverse("api:job_stdout", kwargs={'pk': job.pk}) + "?format=" + format, user=admin, expect=200, format=format)
content = response.data['content'] if format == 'json' else response.data
assert response.data is not None
assert test_data['uri'].username in content

View File

@ -1,6 +1,6 @@
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
#
@ -39,7 +39,7 @@ def test_create_delete_create_user(post, delete, admin):
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)
assert response.status_code == 201
response = delete(reverse('api:user_detail', args=(response.data['id'],)), admin)
response = delete(reverse('api:user_detail', kwargs={'pk': response.data['id']}), admin)
assert response.status_code == 204
response = post(reverse('api:user_list'), EXAMPLE_USER_DATA, admin)

View File

@ -1,12 +1,11 @@
import mock
import pytest
from awx.api.versioning import reverse
from awx.main.models.notifications import NotificationTemplate, Notification
from awx.main.models.inventory import Inventory, Group
from awx.main.models.jobs import JobTemplate
from django.core.urlresolvers import reverse
@pytest.mark.django_db
def test_get_notification_template_list(get, user, notification_template):
@ -29,7 +28,7 @@ def test_basic_parameterization(get, post, user, organization):
headers={"Test": "Header"})),
u)
assert response.status_code == 201
url = reverse('api:notification_template_detail', args=(response.data['id'],))
url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']})
response = get(url, u)
assert 'related' in response.data
assert 'organization' in response.data['related']
@ -60,7 +59,7 @@ def test_encrypted_subfields(get, post, user, organization):
u)
assert response.status_code == 201
notification_template_actual = NotificationTemplate.objects.get(id=response.data['id'])
url = reverse('api:notification_template_detail', args=(response.data['id'],))
url = reverse('api:notification_template_detail', kwargs={'pk': response.data['id']})
response = get(url, u)
assert response.data['notification_configuration']['account_token'] == "$encrypted$"
with mock.patch.object(notification_template_actual.notification_class, "send_messages", assert_send):
@ -89,13 +88,13 @@ def test_inherited_notification_templates(get, post, user, organization, project
g.save()
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
jt.save()
url = reverse('api:organization_notification_templates_any_list', args=(organization.id,))
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
response = post(url, dict(id=notification_templates[0]), u)
assert response.status_code == 204
url = reverse('api:project_notification_templates_any_list', args=(project.id,))
url = reverse('api:project_notification_templates_any_list', kwargs={'pk': project.id})
response = post(url, dict(id=notification_templates[1]), u)
assert response.status_code == 204
url = reverse('api:job_template_notification_templates_any_list', args=(jt.id,))
url = reverse('api:job_template_notification_templates_any_list', kwargs={'pk': jt.id})
response = post(url, dict(id=notification_templates[2]), u)
assert response.status_code == 204
assert len(jt.notification_templates['any']) == 3
@ -113,18 +112,18 @@ def test_notification_template_merging(get, post, user, organization, project, n
@pytest.mark.django_db
def test_notification_template_simple_patch(patch, notification_template, admin):
patch(reverse('api:notification_template_detail', args=(notification_template.id,)), { 'name': 'foo'}, admin, expect=200)
patch(reverse('api:notification_template_detail', kwargs={'pk': notification_template.id}), { 'name': 'foo'}, admin, expect=200)
@pytest.mark.django_db
def test_notification_template_invalid_notification_type(patch, notification_template, admin):
patch(reverse('api:notification_template_detail', args=(notification_template.id,)), { 'notification_type': 'invalid'}, admin, expect=400)
patch(reverse('api:notification_template_detail', kwargs={'pk': notification_template.id}), { 'notification_type': 'invalid'}, admin, expect=400)
@pytest.mark.django_db
def test_disallow_delete_when_notifications_pending(delete, user, notification_template):
u = user('superuser', True)
url = reverse('api:notification_template_detail', args=(notification_template.id,))
url = reverse('api:notification_template_detail', kwargs={'pk': notification_template.id})
Notification.objects.create(notification_template=notification_template,
status='pending')
response = delete(url, user=u)

View File

@ -3,7 +3,7 @@
import mock # noqa
import pytest
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from awx.main.models import Project
@ -38,13 +38,13 @@ def test_user_project_paged_list(get, organization_factory):
# first page has first project and no previous page
pk = objects.users.alice.pk
url = reverse('api:user_projects_list', args=(pk,))
url = reverse('api:user_projects_list', kwargs={'pk':pk,})
results = get(url, objects.users.alice, QUERY_STRING='page_size=1').data
assert results['count'] == 3
assert len(results['results']) == 1
assert results['previous'] is None
assert results['next'] == (
'/api/v1/users/%s/projects/?page=2&page_size=1' % pk
'/api/v2/users/%s/projects/?page=2&page_size=1' % pk
)
# second page has one more, a previous and next page
@ -52,10 +52,10 @@ def test_user_project_paged_list(get, organization_factory):
QUERY_STRING='page=2&page_size=1').data
assert len(results['results']) == 1
assert results['previous'] == (
'/api/v1/users/%s/projects/?page=1&page_size=1' % pk
'/api/v2/users/%s/projects/?page=1&page_size=1' % pk
)
assert results['next'] == (
'/api/v1/users/%s/projects/?page=3&page_size=1' % pk
'/api/v2/users/%s/projects/?page=3&page_size=1' % pk
)
# third page has last project and a previous page
@ -63,7 +63,7 @@ def test_user_project_paged_list(get, organization_factory):
QUERY_STRING='page=3&page_size=1').data
assert len(results['results']) == 1
assert results['previous'] == (
'/api/v1/users/%s/projects/?page=2&page_size=1' % pk
'/api/v2/users/%s/projects/?page=2&page_size=1' % pk
)
assert results['next'] is None
@ -81,7 +81,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
roles=['project-☁-1.admin_role:alice','project-☁-2.admin_role:alice'],
)
pk = objects.users.alice.pk
url = reverse('api:user_projects_list', args=(pk,))
url = reverse('api:user_projects_list', kwargs={'pk':pk,})
# first on first page, next page link contains unicode char
results = get(url, objects.users.alice,
@ -89,7 +89,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
assert results['count'] == 2
assert len(results['results']) == 1
assert results['next'] == (
'/api/v1/users/%s/projects/?page=2&page_size=1&search=%%E2%%98%%81' % pk # noqa
'/api/v2/users/%s/projects/?page=2&page_size=1&search=%%E2%%98%%81' % pk # noqa
)
# second project on second page, previous page link contains unicode char
@ -98,7 +98,7 @@ def test_user_project_paged_list_with_unicode(get, organization_factory):
assert results['count'] == 2
assert len(results['results']) == 1
assert results['previous'] == (
'/api/v1/users/%s/projects/?page=1&page_size=1&search=%%E2%%98%%81' % pk # noqa
'/api/v2/users/%s/projects/?page=1&page_size=1&search=%%E2%%98%%81' % pk # noqa
)
@ -114,21 +114,23 @@ def test_user_project_list(get, organization_factory):
'bob project.admin_role:bob',
'shared project.admin_role:bob',
'shared project.admin_role:alice'])
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.superusers.admin).data['count'] == 3
assert get(reverse(
'api:user_projects_list',
kwargs={'pk':objects.superusers.admin.pk,}
), objects.superusers.admin).data['count'] == 3
# admins can see everyones projects
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.superusers.admin).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.superusers.admin).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.alice.pk,}), objects.superusers.admin).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.bob.pk,}), objects.superusers.admin).data['count'] == 2
# users can see their own projects
assert get(reverse('api:user_projects_list', args=(objects.users.alice.pk,)), objects.users.alice).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.alice.pk,}), objects.users.alice).data['count'] == 2
# alice should only be able to see the shared project when looking at bobs projects
assert get(reverse('api:user_projects_list', args=(objects.users.bob.pk,)), objects.users.alice).data['count'] == 1
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.users.bob.pk,}), objects.users.alice).data['count'] == 1
# alice should see all projects they can see when viewing an admin
assert get(reverse('api:user_projects_list', args=(objects.superusers.admin.pk,)), objects.users.alice).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':objects.superusers.admin.pk,}), objects.users.alice).data['count'] == 2
@pytest.mark.django_db
@ -139,35 +141,35 @@ def test_team_project_list(get, team_project_list):
alice, bob, admin = objects.users.alice, objects.users.bob, objects.superusers.admin
# admins can see all projects on a team
assert get(reverse('api:team_projects_list', args=(team1.pk,)), admin).data['count'] == 2
assert get(reverse('api:team_projects_list', args=(team2.pk,)), admin).data['count'] == 2
assert get(reverse('api:team_projects_list', kwargs={'pk':team1.pk,}), admin).data['count'] == 2
assert get(reverse('api:team_projects_list', kwargs={'pk':team2.pk,}), admin).data['count'] == 2
# users can see all projects on teams they are a member of
assert get(reverse('api:team_projects_list', args=(team1.pk,)), alice).data['count'] == 2
assert get(reverse('api:team_projects_list', kwargs={'pk':team1.pk,}), alice).data['count'] == 2
# but if she does, then she should only see the shared project
team2.read_role.members.add(alice)
assert get(reverse('api:team_projects_list', args=(team2.pk,)), alice).data['count'] == 1
assert get(reverse('api:team_projects_list', kwargs={'pk':team2.pk,}), alice).data['count'] == 1
team2.read_role.members.remove(alice)
# admins can see all projects
assert get(reverse('api:user_projects_list', args=(admin.pk,)), admin).data['count'] == 3
assert get(reverse('api:user_projects_list', kwargs={'pk':admin.pk,}), admin).data['count'] == 3
# admins can see everyones projects
assert get(reverse('api:user_projects_list', args=(alice.pk,)), admin).data['count'] == 2
assert get(reverse('api:user_projects_list', args=(bob.pk,)), admin).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':alice.pk,}), admin).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':bob.pk,}), admin).data['count'] == 2
# users can see their own projects
assert get(reverse('api:user_projects_list', args=(alice.pk,)), alice).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':alice.pk,}), alice).data['count'] == 2
# alice should see all projects they can see when viewing an admin
assert get(reverse('api:user_projects_list', args=(admin.pk,)), alice).data['count'] == 2
assert get(reverse('api:user_projects_list', kwargs={'pk':admin.pk,}), alice).data['count'] == 2
@pytest.mark.django_db
def test_team_project_list_fail1(get, team_project_list):
objects = team_project_list
res = get(reverse('api:team_projects_list', args=(objects.teams.team2.pk,)), objects.users.alice)
res = get(reverse('api:team_projects_list', kwargs={'pk':objects.teams.team2.pk,}), objects.users.alice)
assert res.status_code == 403
@ -210,19 +212,22 @@ def test_create_project_null_organization_xfail(post, organization, org_admin):
@pytest.mark.django_db()
def test_patch_project_null_organization(patch, organization, project, admin):
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': organization.id}, admin, expect=200)
patch(reverse('api:project_detail', kwargs={'pk':project.id,}), { 'name': 't', 'organization': organization.id}, admin, expect=200)
@pytest.mark.django_db()
def test_patch_project_null_organization_xfail(patch, project, org_admin):
patch(reverse('api:project_detail', args=(project.id,)), { 'name': 't', 'organization': None}, org_admin, expect=400)
patch(reverse('api:project_detail', kwargs={'pk':project.id,}), { 'name': 't', 'organization': None}, org_admin, expect=400)
@pytest.mark.django_db
def test_cannot_schedule_manual_project(project, admin_user, post):
response = post(
reverse('api:project_schedules_list', args=(project.pk,)),
{"name": "foo", "description": "", "enabled": True,
reverse('api:project_schedules_list', kwargs={'pk':project.pk,}),
{
"name": "foo", "description": "", "enabled": True,
"rrule": "DTSTART:20160926T040000Z RRULE:FREQ=HOURLY;INTERVAL=1",
"extra_data": {}}, admin_user, expect=400)
"extra_data": {}
}, admin_user, expect=400
)
assert 'Manual' in response.data['unified_job_template'][0]

View File

@ -2,7 +2,7 @@ import mock # noqa
import pytest
from django.db import transaction
from django.core.urlresolvers import reverse
from awx.api.versioning import reverse
from awx.main.models.rbac import Role, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR
@ -78,14 +78,14 @@ def test_roles_filter_visibility(get, organization, project, admin, alice, bob):
Role.singleton('system_auditor').members.add(alice)
project.update_role.members.add(admin)
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=alice).data['count'] == 1
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 0
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=admin).data['count'] == 1
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=alice).data['count'] == 1
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 0
organization.auditor_role.members.add(bob)
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
organization.auditor_role.members.remove(bob)
project.use_role.members.add(bob) # sibling role should still grant visibility
assert get(reverse('api:user_roles_list', args=(admin.id,)) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
assert get(reverse('api:user_roles_list', kwargs={'pk': admin.id}) + '?id=%d' % project.update_role.id, user=bob).data['count'] == 1
@pytest.mark.django_db
@ -104,7 +104,7 @@ def test_cant_delete_role(delete, admin):
# Some day we might want to do this, but until that is speced out, lets
# ensure we don't slip up and allow this implicitly through some helper or
# another
response = delete(reverse('api:role_detail', args=(admin.admin_role.id,)), admin)
response = delete(reverse('api:role_detail', kwargs={'pk': admin.admin_role.id}), admin)
assert response.status_code == 405
@ -115,7 +115,7 @@ def test_cant_delete_role(delete, admin):
@pytest.mark.django_db
def test_get_user_roles_list(get, admin):
url = reverse('api:user_roles_list', args=(admin.id,))
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
response = get(url, admin)
assert response.status_code == 200
roles = response.data
@ -136,7 +136,7 @@ def test_user_view_other_user_roles(organization, inventory, team, get, alice, b
# Bob is an org admin, alice can see this.
# Bob is in a team that alice is not, alice cannot see that bob is a member of that team.
url = reverse('api:user_roles_list', args=(bob.id,))
url = reverse('api:user_roles_list', kwargs={'pk': bob.id})
response = get(url, alice)
assert response.status_code == 200
roles = response.data
@ -171,7 +171,7 @@ def test_user_view_other_user_roles(organization, inventory, team, get, alice, b
@pytest.mark.django_db
def test_add_role_to_user(role, post, admin):
assert admin.roles.filter(id=role.id).count() == 0
url = reverse('api:user_roles_list', args=(admin.id,))
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
response = post(url, {'id': role.id}, admin)
assert response.status_code == 204
@ -189,7 +189,7 @@ def test_add_role_to_user(role, post, admin):
@pytest.mark.django_db
def test_remove_role_from_user(role, post, admin):
assert admin.roles.filter(id=role.id).count() == 0
url = reverse('api:user_roles_list', args=(admin.id,))
url = reverse('api:user_roles_list', kwargs={'pk': admin.id})
response = post(url, {'id': role.id}, admin)
assert response.status_code == 204
assert admin.roles.filter(id=role.id).count() == 1
@ -207,7 +207,7 @@ def test_remove_role_from_user(role, post, admin):
@pytest.mark.django_db
def test_get_teams_roles_list(get, team, organization, admin):
team.member_role.children.add(organization.admin_role)
url = reverse('api:team_roles_list', args=(team.id,))
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
response = get(url, admin)
assert response.status_code == 200
roles = response.data
@ -219,7 +219,7 @@ def test_get_teams_roles_list(get, team, organization, admin):
@pytest.mark.django_db
def test_add_role_to_teams(team, post, admin):
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
url = reverse('api:team_roles_list', args=(team.id,))
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
response = post(url, {'id': team.member_role.id}, admin)
assert response.status_code == 204
@ -237,7 +237,7 @@ def test_add_role_to_teams(team, post, admin):
@pytest.mark.django_db
def test_remove_role_from_teams(team, post, admin):
assert team.member_role.children.filter(id=team.member_role.id).count() == 0
url = reverse('api:team_roles_list', args=(team.id,))
url = reverse('api:team_roles_list', kwargs={'pk': team.id})
response = post(url, {'id': team.member_role.id}, admin)
assert response.status_code == 204
assert team.member_role.children.filter(id=team.member_role.id).count() == 1
@ -254,7 +254,7 @@ def test_remove_role_from_teams(team, post, admin):
@pytest.mark.django_db
def test_get_role(get, admin, role):
url = reverse('api:role_detail', args=(role.id,))
url = reverse('api:role_detail', kwargs={'pk': role.id})
response = get(url, admin)
assert response.status_code == 200
assert response.data['id'] == role.id
@ -262,7 +262,7 @@ def test_get_role(get, admin, role):
@pytest.mark.django_db
def test_put_role_405(put, admin, role):
url = reverse('api:role_detail', args=(role.id,))
url = reverse('api:role_detail', kwargs={'pk': role.id})
response = put(url, {'name': 'Some new name'}, admin)
assert response.status_code == 405
#r = Role.objects.get(id=role.id)
@ -271,7 +271,7 @@ def test_put_role_405(put, admin, role):
@pytest.mark.django_db
def test_put_role_access_denied(put, alice, role):
url = reverse('api:role_detail', args=(role.id,))
url = reverse('api:role_detail', kwargs={'pk': role.id})
response = put(url, {'name': 'Some new name'}, alice)
assert response.status_code == 403 or response.status_code == 405
@ -284,7 +284,7 @@ def test_put_role_access_denied(put, alice, role):
@pytest.mark.django_db
def test_get_role_users(get, admin, role):
role.members.add(admin)
url = reverse('api:role_users_list', args=(role.id,))
url = reverse('api:role_users_list', kwargs={'pk': role.id})
response = get(url, admin)
assert response.status_code == 200
assert response.data['count'] == 1
@ -293,7 +293,7 @@ def test_get_role_users(get, admin, role):
@pytest.mark.django_db
def test_add_user_to_role(post, admin, role):
url = reverse('api:role_users_list', args=(role.id,))
url = reverse('api:role_users_list', kwargs={'pk': role.id})
assert role.members.filter(id=admin.id).count() == 0
post(url, {'id': admin.id}, admin)
assert role.members.filter(id=admin.id).count() == 1
@ -302,7 +302,7 @@ def test_add_user_to_role(post, admin, role):
@pytest.mark.django_db
def test_remove_user_to_role(post, admin, role):
role.members.add(admin)
url = reverse('api:role_users_list', args=(role.id,))
url = reverse('api:role_users_list', kwargs={'pk': role.id})
assert role.members.filter(id=admin.id).count() == 1
post(url, {'disassociate': True, 'id': admin.id}, admin)
assert role.members.filter(id=admin.id).count() == 0
@ -318,7 +318,7 @@ def test_org_admin_add_user_to_job_template(post, organization, check_jobtemplat
assert org_admin in check_jobtemplate.admin_role
assert joe not in check_jobtemplate.execute_role
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, org_admin)
post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'id': joe.id}, org_admin)
assert joe in check_jobtemplate.execute_role
@ -333,7 +333,7 @@ def test_org_admin_remove_user_from_job_template(post, organization, check_jobte
assert org_admin in check_jobtemplate.admin_role
assert joe in check_jobtemplate.execute_role
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, org_admin)
post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'disassociate': True, 'id': joe.id}, org_admin)
assert joe not in check_jobtemplate.execute_role
@ -347,7 +347,7 @@ def test_user_fail_to_add_user_to_job_template(post, organization, check_jobtemp
assert joe not in check_jobtemplate.execute_role
with transaction.atomic():
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, rando)
res = post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'id': joe.id}, rando)
assert res.status_code == 403
assert joe not in check_jobtemplate.execute_role
@ -364,7 +364,7 @@ def test_user_fail_to_remove_user_to_job_template(post, organization, check_jobt
assert joe in check_jobtemplate.execute_role
with transaction.atomic():
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, rando)
res = post(reverse('api:role_users_list', kwargs={'pk': check_jobtemplate.execute_role.id}), {'disassociate': True, 'id': joe.id}, rando)
assert res.status_code == 403
assert joe in check_jobtemplate.execute_role
@ -378,7 +378,7 @@ def test_user_fail_to_remove_user_to_job_template(post, organization, check_jobt
@pytest.mark.django_db
def test_get_role_teams(get, team, admin, role):
role.parents.add(team.member_role)
url = reverse('api:role_teams_list', args=(role.id,))
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
response = get(url, admin)
assert response.status_code == 200
assert response.data['count'] == 1
@ -387,7 +387,7 @@ def test_get_role_teams(get, team, admin, role):
@pytest.mark.django_db
def test_add_team_to_role(post, team, admin, role):
url = reverse('api:role_teams_list', args=(role.id,))
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
assert role.members.filter(id=admin.id).count() == 0
res = post(url, {'id': team.id}, admin)
assert res.status_code == 204
@ -397,7 +397,7 @@ def test_add_team_to_role(post, team, admin, role):
@pytest.mark.django_db
def test_remove_team_from_role(post, team, admin, role):
role.members.add(admin)
url = reverse('api:role_teams_list', args=(role.id,))
url = reverse('api:role_teams_list', kwargs={'pk': role.id})
assert role.members.filter(id=admin.id).count() == 1
res = post(url, {'disassociate': True, 'id': team.id}, admin)
assert res.status_code == 204
@ -412,7 +412,7 @@ def test_remove_team_from_role(post, team, admin, role):
@pytest.mark.django_db
def test_role_parents(get, team, admin, role):
role.parents.add(team.member_role)
url = reverse('api:role_parents_list', args=(role.id,))
url = reverse('api:role_parents_list', kwargs={'pk': role.id})
response = get(url, admin)
assert response.status_code == 200
assert response.data['count'] == 1
@ -427,7 +427,7 @@ def test_role_parents(get, team, admin, role):
@pytest.mark.django_db
def test_role_children(get, team, admin, role):
role.parents.add(team.member_role)
url = reverse('api:role_children_list', args=(team.member_role.id,))
url = reverse('api:role_children_list', kwargs={'pk': team.member_role.id})
response = get(url, admin)
assert response.status_code == 200
assert response.data['count'] == 2
@ -441,7 +441,7 @@ def test_role_children(get, team, admin, role):
@pytest.mark.django_db
def test_ensure_rbac_fields_are_present(organization, get, admin):
url = reverse('api:organization_detail', args=(organization.id,))
url = reverse('api:organization_detail', kwargs={'pk': organization.id})
response = get(url, admin)
assert response.status_code == 200
org = response.data
@ -450,7 +450,7 @@ def test_ensure_rbac_fields_are_present(organization, get, admin):
assert 'object_roles' in org['summary_fields']
role_pk = org['summary_fields']['object_roles']['admin_role']['id']
role_url = reverse('api:role_detail', args=(role_pk,))
role_url = reverse('api:role_detail', kwargs={'pk': role_pk})
org_role_response = get(role_url, admin)
assert org_role_response.status_code == 200
@ -460,7 +460,7 @@ def test_ensure_rbac_fields_are_present(organization, get, admin):
@pytest.mark.django_db
def test_ensure_role_summary_is_present(organization, get, user):
url = reverse('api:organization_detail', args=(organization.id,))
url = reverse('api:organization_detail', kwargs={'pk': organization.id})
response = get(url, user('admin', True))
assert response.status_code == 200
org = response.data

View File

@ -1,6 +1,7 @@
import mock
import pytest
from awx.api.versioning import reverse
from awx.main.access import (
BaseAccess,
JobTemplateAccess,
@ -12,7 +13,6 @@ from awx.main.models.jobs import JobTemplate
from awx.main.models.schedules import Schedule
from django.apps import apps
from django.core.urlresolvers import reverse
@pytest.fixture
@ -250,7 +250,7 @@ def test_job_template_creator_access(project, rando, post):
with mock.patch(
'awx.main.models.projects.ProjectOptions.playbooks',
new_callable=mock.PropertyMock(return_value=['helloworld.yml'])):
response = post(reverse('api:job_template_list', args=[]), dict(
response = post(reverse('api:job_template_list'), dict(
name='newly-created-jt',
job_type='run',
ask_inventory_on_launch=True,

View File

@ -6,7 +6,7 @@ import pytest
def get_related_assert():
def fn(model_obj, related, resource_name, related_resource_name):
assert related_resource_name in related
assert related[related_resource_name] == '/api/v1/%s/%d/%s/' % (resource_name, model_obj.pk, related_resource_name)
assert related[related_resource_name] == '/api/v2/%s/%d/%s/' % (resource_name, model_obj.pk, related_resource_name)
return fn

View File

@ -68,7 +68,7 @@ class TestJobSerializerGetRelated():
def test_job_template_present(self, get_related_mock_and_run, job):
related = get_related_mock_and_run(JobSerializer, job)
assert 'job_template' in related
assert related['job_template'] == '/api/v1/%s/%d/' % ('job_templates', job.job_template.pk)
assert related['job_template'] == '/api/v2/%s/%d/' % ('job_templates', job.job_template.pk)
@mock.patch('awx.api.serializers.BaseSerializer.to_representation', lambda self,obj: {

View File

@ -104,7 +104,7 @@ class TestJobTemplateSerializerGetSummaryFields():
serializer.show_capabilities = ['copy', 'edit']
serializer._summary_field_labels = lambda self: []
serializer._recent_jobs = lambda self: []
request = APIRequestFactory().get('/api/v1/job_templates/42/')
request = APIRequestFactory().get('/api/v2/job_templates/42/')
request.user = user
view = JobTemplateDetail()
view.request = request

View File

@ -56,7 +56,7 @@ class TestWorkflowNodeBaseSerializerGetRelated():
def test_workflow_unified_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
related = get_related_mock_and_run(WorkflowNodeBaseSerializer, workflow_job_template_node_related)
assert 'unified_job_template' in related
assert related['unified_job_template'] == '/api/v1/%s/%d/' % ('job_templates', workflow_job_template_node_related.unified_job_template.pk)
assert related['unified_job_template'] == '/api/v2/%s/%d/' % ('job_templates', workflow_job_template_node_related.unified_job_template.pk)
def test_workflow_unified_job_template_absent(self, workflow_job_template_node):
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
@ -100,7 +100,7 @@ class TestWorkflowJobTemplateNodeSerializerGetRelated():
def test_workflow_job_template_present(self, get_related_mock_and_run, workflow_job_template_node_related):
related = get_related_mock_and_run(WorkflowJobTemplateNodeSerializer, workflow_job_template_node_related)
assert 'workflow_job_template' in related
assert related['workflow_job_template'] == '/api/v1/%s/%d/' % ('workflow_job_templates', workflow_job_template_node_related.workflow_job_template.pk)
assert related['workflow_job_template'] == '/api/v2/%s/%d/' % ('workflow_job_templates', workflow_job_template_node_related.workflow_job_template.pk)
def test_workflow_job_template_absent(self, workflow_job_template_node):
related = WorkflowJobTemplateNodeSerializer().get_related(workflow_job_template_node)
@ -179,7 +179,7 @@ class TestWorkflowJobNodeSerializerGetRelated():
def test_workflow_job_present(self, get_related_mock_and_run, workflow_job_node_related):
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
assert 'workflow_job' in related
assert related['workflow_job'] == '/api/v1/%s/%d/' % ('workflow_jobs', workflow_job_node_related.workflow_job.pk)
assert related['workflow_job'] == '/api/v2/%s/%d/' % ('workflow_jobs', workflow_job_node_related.workflow_job.pk)
def test_workflow_job_absent(self, workflow_job_node):
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)
@ -188,7 +188,7 @@ class TestWorkflowJobNodeSerializerGetRelated():
def test_job_present(self, get_related_mock_and_run, workflow_job_node_related):
related = get_related_mock_and_run(WorkflowJobNodeSerializer, workflow_job_node_related)
assert 'job' in related
assert related['job'] == '/api/v1/%s/%d/' % ('jobs', workflow_job_node_related.job.pk)
assert related['job'] == '/api/v2/%s/%d/' % ('jobs', workflow_job_node_related.job.pk)
def test_job_absent(self, workflow_job_node):
related = WorkflowJobNodeSerializer().get_related(workflow_job_node)

View File

@ -4,7 +4,7 @@ import pytest
from collections import namedtuple
from awx.api.views import (
ApiV1RootView,
ApiVersionRootView,
JobTemplateLabelList,
JobTemplateSurveySpec,
)
@ -17,7 +17,7 @@ def mock_response_new(mocker):
return m
class TestApiV1RootView:
class TestApiRootView:
def test_get_endpoints(self, mocker, mock_response_new):
endpoints = [
'authtoken',
@ -51,7 +51,7 @@ class TestApiV1RootView:
'workflow_job_templates',
'workflow_jobs',
]
view = ApiV1RootView()
view = ApiVersionRootView()
ret = view.get(mocker.MagicMock())
assert ret == mock_response_new

View File

@ -12,7 +12,6 @@ from awx.main.utils.common import ( # noqa
encrypt_field,
parse_yaml_or_json,
decrypt_field,
build_url,
timestamp_apiformat,
model_instance_diff,
model_to_dict,

View File

@ -31,7 +31,6 @@ from django.db.models import ManyToManyField
from rest_framework.exceptions import ParseError, PermissionDenied
from django.utils.encoding import smart_str
from django.utils.text import slugify
from django.core.urlresolvers import reverse
from django.apps import apps
# PyCrypto
@ -736,14 +735,6 @@ def get_pk_from_dict(_dict, key):
return None
def build_url(*args, **kwargs):
get = kwargs.pop('get', {})
url = reverse(*args, **kwargs)
if get:
url += '?' + urllib.urlencode(get)
return url
def timestamp_apiformat(timestamp):
timestamp = timestamp.isoformat()
if timestamp.endswith('+00:00'):

View File

@ -34,7 +34,7 @@
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
{% if user.is_authenticated %}
<li><a href="{% url 'api:user_me_list' %}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Logged in as {{ user }}{% if user.get_full_name %} ({{ user.get_full_name }}){% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="visible-xs-inline">Logged in as </span>{{ user }}{% if user.get_full_name %}<span class="visible-xs-inline"> ({{ user.get_full_name }})</span>{% endif %}</a></li>
<li><a href="{% url 'api:user_me_list' version=request.version %}" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="Logged in as {{ user }}{% if user.get_full_name %} ({{ user.get_full_name }}){% endif %}"><span class="glyphicon glyphicon-user"></span> <span class="visible-xs-inline">Logged in as </span>{{ user }}{% if user.get_full_name %}<span class="visible-xs-inline"> ({{ user.get_full_name }})</span>{% endif %}</a></li>
{% endif %}
<li><a href="//docs.ansible.com/ansible-tower/{{short_tower_version}}/html/towerapi/index.html" target="_blank" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Ansible Tower API Guide' %}"><span class="glyphicon glyphicon-question-sign"></span><span class="visible-xs-inline">{% trans 'Ansible Tower API Guide' %}</span></a></li>
<li><a href="/" data-toggle="tooltip" data-placement="bottom" data-delay="1000" title="{% trans 'Back to Ansible Tower' %}"><span class="glyphicon glyphicon-circle-arrow-left"></span><span class="visible-xs-inline">{% trans 'Back to Ansible Tower' %}</span></a></li>