Skip to content

Commit

Permalink
Get "related" working for application tokens
Browse files Browse the repository at this point in the history
Signed-off-by: Rick Elrod <[email protected]>
  • Loading branch information
relrod committed Apr 22, 2024
1 parent 2f55591 commit 5dbf5b2
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.11 on 2024-04-21 15:48

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('dab_oauth2_provider', '0002_alter_oauth2accesstoken_created_and_more'),
]

operations = [
migrations.AlterField(
model_name='oauth2accesstoken',
name='application',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='access_tokens', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
),
]
15 changes: 10 additions & 5 deletions ansible_base/oauth2_provider/models/access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@


class OAuth2AccessToken(oauth2_models.AbstractAccessToken, CommonModel):
reverse_name_override = 'token'
# There is a special condition where, as the user is logging in we want to update the last_used field.
# However, this happens before the user is set for the request.
# If this is the only field attempting to be saved, don't update the modified on/by fields
not_user_modified_fields = ['last_used']
router_basename = 'token'
ignore_relations = ['refresh_token']

class Meta(oauth2_models.AbstractAccessToken.Meta):
verbose_name = _('access token')
Expand All @@ -30,6 +27,14 @@ class Meta(oauth2_models.AbstractAccessToken.Meta):
related_name="%(app_label)s_%(class)s",
help_text=_('The user representing the token owner'),
)
# Overriding to set related_name
application = models.ForeignKey(
settings.OAUTH2_PROVIDER_APPLICATION_MODEL,
on_delete=models.CASCADE,
blank=True,
null=True,
related_name='access_tokens',
)
description = models.TextField(
default='',
blank=True,
Expand Down
5 changes: 3 additions & 2 deletions ansible_base/oauth2_provider/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@


class OAuth2Application(oauth2_models.AbstractApplication, NamedCommonModel):
reverse_name_override = 'application'
router_basename = 'application'
ignore_relations = ['oauth2idtoken', 'grant', 'oauth2refreshtoken']
encrypted_fields = ['client_secret']

class Meta(oauth2_models.AbstractAccessToken.Meta):
Expand Down Expand Up @@ -67,4 +68,4 @@ class Meta(oauth2_models.AbstractAccessToken.Meta):
def get_absolute_url(self):
# This is kind of annoying. This method lives on the superclass and we check for it in CommonModel.
# But better would be to not have this method and let the CommonModel logic fall back to the "right" way of finding this.
return reverse('application-detail', kwargs={'pk': self.pk})
return reverse(f'{self.router_basename}-detail', kwargs={'pk': self.pk})
1 change: 0 additions & 1 deletion ansible_base/oauth2_provider/serializers/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@


class BaseOAuth2TokenSerializer(CommonModelSerializer):
reverse_url_name = 'token-detail'
refresh_token = SerializerMethodField()
token = SerializerMethodField()
ALLOWED_SCOPES = ['read', 'write']
Expand Down
33 changes: 14 additions & 19 deletions ansible_base/oauth2_provider/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,25 @@

router = AssociationResourceRouter()

router.register(r'applications', oauth2_provider_views.OAuth2ApplicationViewSet, basename='application')

router.register(r'tokens', oauth2_provider_views.OAuth2TokenViewSet, basename='token')
router.register(
r'applications',
oauth2_provider_views.OAuth2ApplicationViewSet,
basename='application',
related_views={
'tokens': (oauth2_provider_views.OAuth2TokenViewSet, 'access_tokens'),
},
)

router.register(
r'tokens',
oauth2_provider_views.OAuth2TokenViewSet,
basename='token',
)

api_version_urls = [
path('', include(router.urls)),
]

# re_path(
# r'^applications/(?P<pk>[0-9]+)/tokens/$',
# oauth2_provider_views.ApplicationOAuth2TokenList.as_view(),
# name='o_auth2_application_token_list'
# ),
# re_path(
# r'^applications/(?P<pk>[0-9]+)/activity_stream/$',
# oauth2_provider_views.OAuth2ApplicationActivityStreamList.as_view(),
# name='o_auth2_application_activity_stream_list'
# ),
# re_path(
# r'^tokens/(?P<pk>[0-9]+)/activity_stream/$',
# oauth2_provider_views.OAuth2TokenActivityStreamList.as_view(),
# name='o_auth2_token_activity_stream_list'
# ),

root_urls = [
re_path(r'^o/$', oauth2_provider_views.ApiOAuthAuthorizationRootView.as_view(), name='oauth_authorization_root_view'),
re_path(r"^o/authorize/$", oauth_views.AuthorizationView.as_view(), name="authorize"),
Expand Down
29 changes: 0 additions & 29 deletions ansible_base/oauth2_provider/views/token_root.py

This file was deleted.

34 changes: 34 additions & 0 deletions test_app/tests/oauth2_provider/views/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,40 @@ def test_oauth2_provider_application_list(request, client_fixture, expected_stat
assert response.data['results'][0]['name'] == oauth2_application.name


@pytest.mark.parametrize(
"view, path",
[
("application-list", lambda data: data['results'][0]),
("application-detail", lambda data: data),
],
)
def test_oauth2_provider_application_related(admin_api_client, oauth2_application, organization, view, path):
"""
Test that the related fields are correct.
Organization should only be shown if the application is associated with an organization.
Associating an application with an organization should not affect other related fields.
"""
if view == "application-list":
url = reverse(view)
else:
url = reverse(view, args=[oauth2_application.pk])

oauth2_application.organization = None
oauth2_application.save()
response = admin_api_client.get(url)
assert response.status_code == 200
assert path(response.data)['related']['access_tokens'] == reverse("application-access_tokens-list", args=[oauth2_application.pk])
assert 'organization' not in path(response.data)['related']

oauth2_application.organization = organization
oauth2_application.save()
response = admin_api_client.get(url)
assert response.status_code == 200
assert path(response.data)['related']['access_tokens'] == reverse("application-access_tokens-list", args=[oauth2_application.pk])
assert path(response.data)['related']['organization'] == reverse("organization-detail", args=[organization.pk])


@pytest.mark.parametrize(
"client_fixture,expected_status",
[
Expand Down

0 comments on commit 5dbf5b2

Please sign in to comment.