Merge pull request #6272 from normanjaeckel/GetUser

Added route to get a user e. g. for third-party applications.
This commit is contained in:
Emanuel Schütze 2021-11-22 17:32:04 +01:00 committed by GitHub
commit d4953ed81a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 135 additions and 5 deletions

View File

@ -2,7 +2,6 @@ name: CI
on: on:
pull_request: pull_request:
branches: [master]
jobs: jobs:
test-server: test-server:

View File

@ -109,7 +109,7 @@ export class VideoPlayerComponent implements AfterViewInit, OnDestroy {
} }
public get nanocosmosVideoUrl(): string { public get nanocosmosVideoUrl(): string {
return `https://demo.nanocosmos.de/nanoplayer/embed/1.0.0/nanoplayer.html?entry.rtmp.streamname=${this.videoId}`; return `https://demo.nanocosmos.de/nanoplayer/embed/1.0.0/nanoplayer.html?entry.rtmp.streamname=${this.videoId}`; // tslint:disable
} }
public constructor( public constructor(
@ -237,7 +237,7 @@ export class VideoPlayerComponent implements AfterViewInit, OnDestroy {
} }
private getNanocosmosVideoId(url: string): string { private getNanocosmosVideoId(url: string): string {
const urlParts: Array<String> = url.split('='); const urlParts: String[] = url.split('=');
if (urlParts?.length && typeof urlParts[1] === 'string') { if (urlParts?.length && typeof urlParts[1] === 'string') {
return urlParts[1]; return urlParts[1];
} }

View File

@ -20,4 +20,9 @@ urlpatterns = [
views.PasswordResetConfirmView.as_view(), views.PasswordResetConfirmView.as_view(),
name="password_reset_confirm", name="password_reset_confirm",
), ),
url(
r"^get-user/$",
views.GetUserView.as_view(),
name="get_user",
),
] ]

View File

@ -39,6 +39,7 @@ from ..utils.autoupdate import AutoupdateElement, inform_changed_data, inform_el
from ..utils.cache import element_cache from ..utils.cache import element_cache
from ..utils.rest_api import ( from ..utils.rest_api import (
ModelViewSet, ModelViewSet,
NotFound,
Response, Response,
SimpleMetadata, SimpleMetadata,
ValidationError, ValidationError,
@ -1168,3 +1169,61 @@ class PasswordResetConfirmView(APIView):
except (TypeError, ValueError, OverflowError, User.DoesNotExist): except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None user = None
return user return user
class GetUserView(APIView):
"""
View to retrieve a single user.
Use query parameters "id", "username", "email" or "number" to look for
a user and retrieve its data.
"""
http_method_names = ["get"]
def get(self, request, *args, **kwargs):
# Check permissions.
if not request.user.is_authenticated or not has_perm(
request.user, "users.can_manage"
):
self.permission_denied(request)
# Parse parameters
params = request.GET
user_id = params.get("id", "0")
try:
user_id = int(user_id)
except ValueError:
raise ValidationError({"detail": "Invalid parameter user_id."})
email = params.get("email", "")
username = params.get("username", "")
number = params.get("number", "")
# Build queryset
query = User.objects.all()
if user_id:
query = query.filter(pk=user_id)
if username:
query = query.filter(username=username)
if email:
query = query.filter(email=email)
if number:
query = query.filter(number=number)
# Execute queryset
try:
self.user = query.get()
except User.DoesNotExist:
raise NotFound({"detail": "User does not exist."})
except User.MultipleObjectsReturned:
raise ValidationError({"detail": "Found more than one user."})
return super().get(request, *args, **kwargs)
def get_context_data(self, **context):
user_full_data = async_to_sync(element_cache.get_element_data)(
self.user.get_collection_string(), self.user.pk
)
user_full_data.pop("session_auth_hash")
context.update({"user": user_full_data})
return context

View File

@ -4,7 +4,7 @@ from typing import Any, Dict, Iterable, Type
from django.db.models import Model from django.db.models import Model
from rest_framework import status from rest_framework import status
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException, NotFound, ValidationError
from rest_framework.metadata import SimpleMetadata from rest_framework.metadata import SimpleMetadata
from rest_framework.mixins import ( from rest_framework.mixins import (
CreateModelMixin as _CreateModelMixin, CreateModelMixin as _CreateModelMixin,
@ -33,7 +33,6 @@ from rest_framework.serializers import (
Serializer, Serializer,
SerializerMetaclass, SerializerMetaclass,
SerializerMethodField, SerializerMethodField,
ValidationError,
) )
from rest_framework.utils.serializer_helpers import ReturnDict from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework.viewsets import GenericViewSet as _GenericViewSet from rest_framework.viewsets import GenericViewSet as _GenericViewSet
@ -59,6 +58,7 @@ __all__ = [
"RelatedField", "RelatedField",
"SerializerMethodField", "SerializerMethodField",
"ValidationError", "ValidationError",
"NotFound",
] ]

View File

@ -162,3 +162,70 @@ class TestUserLoginView(TestCase):
self.assertEqual( self.assertEqual(
content.get("detail"), "Cookies have to be enabled to use OpenSlides." content.get("detail"), "Cookies have to be enabled to use OpenSlides."
) )
class TestGetUserView(TestCase):
url = reverse("get_user")
def setUp(self):
pass
def test_get_anonymous(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 403)
content = json.loads(response.content.decode())
self.assertEqual(
content.get("detail"), "Authentication credentials were not provided."
)
def test_get_authenticated_user(self):
self.client.login(username="admin", password="admin")
response = self.client.get(self.url, {"username": "admin"})
self.assertEqual(response.status_code, 200)
user = json.loads(response.content.decode()).get("user")
self.assertEqual(user["username"], "admin")
self.assertEqual(user["last_name"], "Administrator")
def test_post(self):
response = self.client.post(self.url)
self.assertEqual(response.status_code, 405)
def test_not_found(self):
self.client.login(username="admin", password="admin")
response = self.client.get(self.url, {"username": "not-existing-username"})
self.assertEqual(response.status_code, 404)
content = json.loads(response.content.decode())
self.assertEqual(content.get("detail"), "User does not exist.")
def test_multiple_objects(self):
self.client.login(username="admin", password="admin")
u1, p1 = self.create_user()
u1.number = "Number#1234567890"
u1.save()
u2, p2 = self.create_user()
u2.number = "Number#1234567890"
u2.save()
response = self.client.get(self.url, {"number": "Number#1234567890"})
self.assertEqual(response.status_code, 400)
content = json.loads(response.content.decode())
self.assertEqual(content.get("detail"), "Found more than one user.")
def test_delegate(self):
self.make_admin_delegate()
self.client.login(username="admin", password="admin")
response = self.client.get(self.url, {"username": "admin"})
self.assertEqual(response.status_code, 403)
content = json.loads(response.content.decode())
self.assertEqual(
content.get("detail"), "You do not have permission to perform this action."
)