Merge pull request #6272 from normanjaeckel/GetUser
Added route to get a user e. g. for third-party applications.
This commit is contained in:
commit
d4953ed81a
1
.github/workflows/run-tests.yml
vendored
1
.github/workflows/run-tests.yml
vendored
@ -2,7 +2,6 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [master]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-server:
|
test-server:
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -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."
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user