Skip to content
Snippets Groups Projects
Commit fcaf1b8c authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Implemented a basic API endpoint to fetch user data and relevant permissions

parent 5ed8fb50
No related branches found
No related tags found
No related merge requests found
...@@ -20,6 +20,7 @@ urlpatterns += [ ...@@ -20,6 +20,7 @@ urlpatterns += [
url(r'^search$', views.Search.as_view(), name='search'), url(r'^search$', views.Search.as_view(), name='search'),
url(r'^radios/', include('funkwhale_api.radios.urls', namespace='radios')), url(r'^radios/', include('funkwhale_api.radios.urls', namespace='radios')),
url(r'^history/', include('funkwhale_api.history.urls', namespace='history')), url(r'^history/', include('funkwhale_api.history.urls', namespace='history')),
url(r'^users/', include('funkwhale_api.users.api_urls', namespace='users')),
url(r'^token/', 'rest_framework_jwt.views.obtain_jwt_token'), url(r'^token/', 'rest_framework_jwt.views.obtain_jwt_token'),
url(r'^token/refresh/', 'rest_framework_jwt.views.refresh_jwt_token'), url(r'^token/refresh/', 'rest_framework_jwt.views.refresh_jwt_token'),
] ]
from rest_framework import routers
from . import views
router = routers.SimpleRouter()
router.register(r'users', views.UserViewSet, 'users')
urlpatterns = router.urls
...@@ -15,6 +15,14 @@ class User(AbstractUser): ...@@ -15,6 +15,14 @@ class User(AbstractUser):
# around the globe. # around the globe.
name = models.CharField(_("Name of User"), blank=True, max_length=255) name = models.CharField(_("Name of User"), blank=True, max_length=255)
# permissions that are used for API access and that worth serializing
relevant_permissions = {
# internal_codename : {external_codename}
'music.add_importbatch': {
'external_codename': 'import.launch'
}
}
def __str__(self): def __str__(self):
return self.username return self.username
......
from rest_framework import serializers
from . import models
class UserSerializer(serializers.ModelSerializer):
permissions = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = [
'id',
'username',
'name',
'email',
'is_staff',
'is_superuser',
'permissions',
]
def get_permissions(self, o):
perms = {}
for internal_codename, conf in o.relevant_permissions.items():
perms[conf['external_codename']] = {
'status': o.has_perm(internal_codename)
}
return perms
import factory import factory
from django.contrib.auth.models import Permission
class UserFactory(factory.django.DjangoModelFactory): class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: 'user-{0}'.format(n)) username = factory.Sequence(lambda n: 'user-{0}'.format(n))
...@@ -9,3 +11,20 @@ class UserFactory(factory.django.DjangoModelFactory): ...@@ -9,3 +11,20 @@ class UserFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
model = 'users.User' model = 'users.User'
django_get_or_create = ('username', ) django_get_or_create = ('username', )
@factory.post_generation
def perms(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
perms = [
Permission.objects.get(
content_type__app_label=p.split('.')[0],
codename=p.split('.')[1],
)
for p in extracted
]
# A list of permissions were passed in, use them
self.user_permissions.add(*perms)
import json
from django.test import RequestFactory from django.test import RequestFactory
from test_plus.test import TestCase from test_plus.test import TestCase
from funkwhale_api.users.models import User from funkwhale_api.users.models import User
from . factories import UserFactory
class UserTestCase(TestCase): class UserTestCase(TestCase):
...@@ -36,3 +40,26 @@ class UserTestCase(TestCase): ...@@ -36,3 +40,26 @@ class UserTestCase(TestCase):
with self.settings(REGISTRATION_MODE="disabled"): with self.settings(REGISTRATION_MODE="disabled"):
response = self.client.post(url, data) response = self.client.post(url, data)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
def test_can_fetch_data_from_api(self):
url = self.reverse('api:users:users-me')
response = self.client.get(url)
# login required
self.assertEqual(response.status_code, 401)
user = UserFactory(is_staff=True, perms=['music.add_importbatch'])
self.assertTrue(user.has_perm('music.add_importbatch'))
self.login(user)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
payload = json.loads(response.content.decode('utf-8'))
self.assertEqual(payload['username'], user.username)
self.assertEqual(payload['is_staff'], user.is_staff)
self.assertEqual(payload['is_superuser'], user.is_superuser)
self.assertEqual(payload['email'], user.email)
self.assertEqual(payload['name'], user.name)
self.assertEqual(
payload['permissions']['import.launch']['status'], True)
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import viewsets
from rest_framework.decorators import list_route
from rest_auth.registration.views import RegisterView as BaseRegisterView from rest_auth.registration.views import RegisterView as BaseRegisterView
from allauth.account.adapter import get_adapter from allauth.account.adapter import get_adapter
from . import models
from . import serializers
class RegisterView(BaseRegisterView): class RegisterView(BaseRegisterView):
...@@ -15,3 +21,14 @@ class RegisterView(BaseRegisterView): ...@@ -15,3 +21,14 @@ class RegisterView(BaseRegisterView):
def is_open_for_signup(self, request): def is_open_for_signup(self, request):
return get_adapter().is_open_for_signup(request) return get_adapter().is_open_for_signup(request)
class UserViewSet(viewsets.GenericViewSet):
queryset = models.User.objects.all()
serializer_class = serializers.UserSerializer
@list_route(methods=['get'])
def me(self, request, *args, **kwargs):
"""Return information about the current user"""
serializer = self.serializer_class(request.user)
return Response(serializer.data)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment