✨(project) add CRUD API endpoints for Rooms and ResourceAccess models
Introduce CRUD API endpoints for the Rooms and ResourceAccess models. The code follows the Magnify logic, with the exception that token generation has been removed and replaced by a TODO item with a mocked value. Proper integration of LiveKit will be added in future commits. With the removal of group logic, some complex query sets can be simplified. Previously, we checked for both direct and indirect access to a room. Indirect access meant a room was shared with a group, and the user was a member of that group. I haven’t simplified those query set, as I preferred isolate changes in dedicated commits. Additionally, all previous tests are still passing, although tests related to groups have been removed.
This commit is contained in:
@@ -62,3 +62,17 @@ class UserAdmin(auth_admin.UserAdmin):
|
||||
ordering = ("is_active", "-is_superuser", "-is_staff", "-is_device", "-updated_at")
|
||||
readonly_fields = ("id", "sub", "email", "created_at", "updated_at")
|
||||
search_fields = ("id", "sub", "admin_email", "email")
|
||||
|
||||
|
||||
class ResourceAccessInline(admin.TabularInline):
|
||||
"""Admin class for the room user access model"""
|
||||
|
||||
model = models.ResourceAccess
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(models.Room)
|
||||
class RoomAdmin(admin.ModelAdmin):
|
||||
"""Room admin interface declaration."""
|
||||
|
||||
inlines = (ResourceAccessInline,)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Permission handlers for the impress core app."""
|
||||
from rest_framework import permissions
|
||||
|
||||
from ..models import RoleChoices
|
||||
|
||||
ACTION_FOR_METHOD_TO_PERMISSION = {
|
||||
"versions_detail": {"DELETE": "versions_destroy", "GET": "versions_retrieve"}
|
||||
}
|
||||
@@ -34,3 +36,49 @@ class IsSelf(IsAuthenticated):
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""Write permissions are only allowed to the user itself."""
|
||||
return obj == request.user
|
||||
|
||||
|
||||
class RoomPermissions(permissions.BasePermission):
|
||||
"""
|
||||
Permissions applying to the room API endpoint.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
"""Only allow authenticated users for unsafe methods."""
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
return request.user.is_authenticated
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""Object permissions are only given to administrators of the room."""
|
||||
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
user = request.user
|
||||
|
||||
if request.method == "DELETE":
|
||||
return obj.is_owner(user)
|
||||
|
||||
return obj.is_administrator(user)
|
||||
|
||||
|
||||
class ResourceAccessPermission(permissions.BasePermission):
|
||||
"""
|
||||
Permissions for a room that can only be updated by room administrators.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
"""Only allow authenticated users."""
|
||||
return request.user.is_authenticated
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
"""
|
||||
Check that the logged-in user is administrator of the linked room.
|
||||
"""
|
||||
user = request.user
|
||||
if request.method == "DELETE" and obj.role == RoleChoices.OWNER:
|
||||
return obj.user == user
|
||||
|
||||
return obj.resource.is_administrator(user)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""Client serializers for the impress core app."""
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from core import models
|
||||
|
||||
@@ -11,3 +14,120 @@ class UserSerializer(serializers.ModelSerializer):
|
||||
model = models.User
|
||||
fields = ["id", "email"]
|
||||
read_only_fields = ["id", "email"]
|
||||
|
||||
|
||||
class ResourceAccessSerializerMixin:
|
||||
"""
|
||||
A serializer mixin to share controlling that the logged-in user submitting a room access object
|
||||
is administrator on the targeted room.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-many-boolean-expressions
|
||||
def validate(self, data):
|
||||
"""
|
||||
Check access rights specific to writing (create/update)
|
||||
"""
|
||||
request = self.context.get("request", None)
|
||||
user = getattr(request, "user", None)
|
||||
if (
|
||||
# Update
|
||||
self.instance
|
||||
and (
|
||||
data["role"] == models.RoleChoices.OWNER
|
||||
and not self.instance.resource.is_owner(user)
|
||||
or self.instance.role == models.RoleChoices.OWNER
|
||||
and not self.instance.user == user
|
||||
)
|
||||
) or (
|
||||
# Create
|
||||
not self.instance
|
||||
and data.get("role") == models.RoleChoices.OWNER
|
||||
and not data["resource"].is_owner(user)
|
||||
):
|
||||
raise PermissionDenied(
|
||||
"Only owners of a room can assign other users as owners."
|
||||
)
|
||||
return data
|
||||
|
||||
def validate_resource(self, resource):
|
||||
"""The logged-in user must be administrator of the resource."""
|
||||
request = self.context.get("request", None)
|
||||
user = getattr(request, "user", None)
|
||||
|
||||
if not (user and user.is_authenticated and resource.is_administrator(user)):
|
||||
raise PermissionDenied(
|
||||
_("You must be administrator or owner of a room to add accesses to it.")
|
||||
)
|
||||
|
||||
return resource
|
||||
|
||||
|
||||
class ResourceAccessSerializer(
|
||||
ResourceAccessSerializerMixin, serializers.ModelSerializer
|
||||
):
|
||||
"""Serialize Room to User accesses for the API."""
|
||||
|
||||
class Meta:
|
||||
model = models.ResourceAccess
|
||||
fields = ["id", "user", "resource", "role"]
|
||||
read_only_fields = ["id"]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""Make "user" and "resource" fields readonly but only on update."""
|
||||
validated_data.pop("resource", None)
|
||||
validated_data.pop("user", None)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class NestedResourceAccessSerializer(ResourceAccessSerializer):
|
||||
"""Serialize Room accesses for the API with full nested user."""
|
||||
|
||||
user = UserSerializer(read_only=True)
|
||||
|
||||
|
||||
class RoomSerializer(serializers.ModelSerializer):
|
||||
"""Serialize Room model for the API."""
|
||||
|
||||
class Meta:
|
||||
model = models.Room
|
||||
fields = ["id", "name", "slug", "configuration", "is_public"]
|
||||
read_only_fields = ["id", "slug"]
|
||||
|
||||
def to_representation(self, instance):
|
||||
"""
|
||||
Add users only for administrator users.
|
||||
Add LiveKit credentials for public instance or related users/groups
|
||||
"""
|
||||
output = super().to_representation(instance)
|
||||
request = self.context.get("request")
|
||||
|
||||
if not request:
|
||||
return output
|
||||
|
||||
role = instance.get_role(request.user)
|
||||
is_admin = models.RoleChoices.check_administrator_role(role)
|
||||
|
||||
if role is not None:
|
||||
access_serializer = NestedResourceAccessSerializer(
|
||||
instance.accesses.select_related("resource", "user").all(),
|
||||
context=self.context,
|
||||
many=True,
|
||||
)
|
||||
output["accesses"] = access_serializer.data
|
||||
|
||||
if not is_admin:
|
||||
del output["configuration"]
|
||||
|
||||
if role is not None or instance.is_public:
|
||||
output["livekit"] = {
|
||||
# todo - generate a proper livekit name
|
||||
"room": "foo",
|
||||
# todo - generate a proper token
|
||||
"token": "foo",
|
||||
}
|
||||
|
||||
output["is_administrable"] = is_admin
|
||||
|
||||
# todo - pass properly livekit configuration
|
||||
|
||||
return output
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
"""API endpoints"""
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.text import slugify
|
||||
|
||||
from rest_framework import (
|
||||
decorators,
|
||||
mixins,
|
||||
@@ -140,3 +148,131 @@ class UserViewSet(
|
||||
return drf_response.Response(
|
||||
self.serializer_class(request.user, context=context).data
|
||||
)
|
||||
|
||||
|
||||
class RoomViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
viewsets.GenericViewSet,
|
||||
):
|
||||
"""
|
||||
API endpoints to access and perform actions on rooms.
|
||||
"""
|
||||
|
||||
permission_classes = [permissions.RoomPermissions]
|
||||
queryset = models.Room.objects.all()
|
||||
serializer_class = serializers.RoomSerializer
|
||||
|
||||
def get_object(self):
|
||||
"""Allow getting a room by its slug."""
|
||||
try:
|
||||
uuid.UUID(self.kwargs["pk"])
|
||||
filter_kwargs = {"pk": self.kwargs["pk"]}
|
||||
except ValueError:
|
||||
filter_kwargs = {"slug": slugify(self.kwargs["pk"])}
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
obj = get_object_or_404(queryset, **filter_kwargs)
|
||||
# May raise a permission denied
|
||||
self.check_object_permissions(self.request, obj)
|
||||
return obj
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
"""
|
||||
Allow unregistered rooms when activated.
|
||||
For unregistered rooms we only return a null id and the livekit room and token.
|
||||
"""
|
||||
try:
|
||||
instance = self.get_object()
|
||||
except Http404:
|
||||
if not settings.ALLOW_UNREGISTERED_ROOMS:
|
||||
raise
|
||||
slug = slugify(self.kwargs["pk"])
|
||||
data = {
|
||||
"id": None,
|
||||
"livekit": {
|
||||
"room": slug,
|
||||
# todo - generate a proper token
|
||||
"token": "foo",
|
||||
},
|
||||
}
|
||||
else:
|
||||
data = self.get_serializer(instance).data
|
||||
|
||||
return drf_response.Response(data)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Limit listed rooms to the ones related to the authenticated user."""
|
||||
user = self.request.user
|
||||
|
||||
if user.is_authenticated:
|
||||
# todo - simplify this queryset
|
||||
queryset = (
|
||||
self.filter_queryset(self.get_queryset())
|
||||
.filter(Q(users=user))
|
||||
.distinct()
|
||||
)
|
||||
else:
|
||||
queryset = self.get_queryset().none()
|
||||
|
||||
page = self.paginate_queryset(queryset)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
return drf_response.Response(serializer.data)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Set the current user as owner of the newly created room."""
|
||||
room = serializer.save()
|
||||
models.ResourceAccess.objects.create(
|
||||
resource=room,
|
||||
user=self.request.user,
|
||||
role=models.RoleChoices.OWNER,
|
||||
)
|
||||
|
||||
|
||||
class ResourceAccessListModelMixin:
|
||||
"""List mixin for resource access API."""
|
||||
|
||||
def get_permissions(self):
|
||||
"""User only needs to be authenticated to list rooms access"""
|
||||
if self.action == "list":
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
else:
|
||||
return super().get_permissions()
|
||||
|
||||
return [permission() for permission in permission_classes]
|
||||
|
||||
def get_queryset(self):
|
||||
"""Return the queryset according to the action."""
|
||||
queryset = super().get_queryset()
|
||||
if self.action == "list":
|
||||
user = self.request.user
|
||||
queryset = queryset.filter(
|
||||
Q(resource__accesses__user=user),
|
||||
resource__accesses__role__in=[
|
||||
models.RoleChoices.ADMIN,
|
||||
models.RoleChoices.OWNER,
|
||||
],
|
||||
).distinct()
|
||||
return queryset
|
||||
|
||||
|
||||
class ResourceAccessViewSet(
|
||||
ResourceAccessListModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
viewsets.GenericViewSet,
|
||||
):
|
||||
"""
|
||||
API endpoints to access and perform actions on resource accesses.
|
||||
"""
|
||||
|
||||
permission_classes = [permissions.ResourceAccessPermission]
|
||||
queryset = models.ResourceAccess.objects.all()
|
||||
serializer_class = serializers.ResourceAccessSerializer
|
||||
|
||||
0
src/backend/core/tests/rooms/__init__.py
Normal file
0
src/backend/core/tests/rooms/__init__.py
Normal file
71
src/backend/core/tests/rooms/test_api_rooms_create.py
Normal file
71
src/backend/core/tests/rooms/test_api_rooms_create.py
Normal file
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
Test rooms API endpoints in the impress core app: create.
|
||||
"""
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ...factories import RoomFactory, UserFactory
|
||||
from ...models import Room
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_rooms_create_anonymous():
|
||||
"""Anonymous users should not be allowed to create rooms."""
|
||||
client = APIClient()
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/rooms/",
|
||||
{
|
||||
"name": "my room",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert Room.objects.exists() is False
|
||||
|
||||
|
||||
def test_api_rooms_create_authenticated():
|
||||
"""
|
||||
Authenticated users should be able to create rooms and should automatically be declared
|
||||
as owner of the newly created room.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/rooms/",
|
||||
{
|
||||
"name": "my room",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
room = Room.objects.get()
|
||||
assert room.name == "my room"
|
||||
assert room.slug == "my-room"
|
||||
assert room.accesses.filter(role="owner", user=user).exists() is True
|
||||
|
||||
|
||||
def test_api_rooms_create_authenticated_existing_slug():
|
||||
"""
|
||||
A user trying to create a room with a name that translates to a slug that already exists
|
||||
should receive a 400 error.
|
||||
"""
|
||||
RoomFactory(name="my room")
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/rooms/",
|
||||
{
|
||||
"name": "My Room!",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"slug": ["Room with this Slug already exists."]}
|
||||
101
src/backend/core/tests/rooms/test_api_rooms_delete.py
Normal file
101
src/backend/core/tests/rooms/test_api_rooms_delete.py
Normal file
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
Test rooms API endpoints in the impress core app: delete.
|
||||
"""
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ...factories import RoomFactory, UserFactory
|
||||
from ...models import Room
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_rooms_delete_anonymous():
|
||||
"""Anonymous users should not be allowed to destroy a room."""
|
||||
room = RoomFactory()
|
||||
client = APIClient()
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert Room.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_rooms_delete_authenticated():
|
||||
"""
|
||||
Authenticated users should not be allowed to delete a room to which they are not
|
||||
related.
|
||||
"""
|
||||
room = RoomFactory()
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert Room.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_rooms_delete_members():
|
||||
"""
|
||||
Authenticated users should not be allowed to delete a room for which they are
|
||||
only a member.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(
|
||||
users=[(user, "member")]
|
||||
) # as user declared in the room but not administrator
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/rooms/{room.id}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert Room.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_rooms_delete_administrators():
|
||||
"""
|
||||
Authenticated users should not be allowed to delete a room for which they are
|
||||
administrator.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/rooms/{room.id}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert Room.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_rooms_delete_owners():
|
||||
"""
|
||||
Authenticated users should be able to delete a room for which they are directly
|
||||
owner.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/rooms/{room.id}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 204
|
||||
assert Room.objects.exists() is False
|
||||
116
src/backend/core/tests/rooms/test_api_rooms_list.py
Normal file
116
src/backend/core/tests/rooms/test_api_rooms_list.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Test rooms API endpoints in the impress core app: list.
|
||||
"""
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ...factories import RoomFactory, UserFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_rooms_list_anonymous():
|
||||
"""Anonymous users should not be able to list rooms."""
|
||||
RoomFactory(is_public=False)
|
||||
RoomFactory(is_public=True)
|
||||
|
||||
client = APIClient()
|
||||
|
||||
response = client.get("/api/v1.0/rooms/")
|
||||
assert response.status_code == 200
|
||||
|
||||
results = response.json()["results"]
|
||||
assert len(results) == 0
|
||||
|
||||
|
||||
def test_api_rooms_list_authenticated():
|
||||
"""
|
||||
Authenticated users listing rooms, should only see the rooms
|
||||
to which they are related.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
other_user = UserFactory()
|
||||
|
||||
RoomFactory(is_public=False)
|
||||
RoomFactory(is_public=True)
|
||||
room_user_accesses = RoomFactory(is_public=False, users=[user])
|
||||
RoomFactory(is_public=False, users=[other_user])
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/rooms/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
results = response.json()["results"]
|
||||
assert len(results) == 1
|
||||
expected_ids = {
|
||||
str(room_user_accesses.id),
|
||||
}
|
||||
results_id = {result["id"] for result in results}
|
||||
assert expected_ids == results_id
|
||||
|
||||
|
||||
@mock.patch.object(PageNumberPagination, "get_page_size", return_value=2)
|
||||
def test_api_rooms_list_pagination(_mock_page_size):
|
||||
"""Pagination should work as expected."""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
rooms = RoomFactory.create_batch(3, users=[user])
|
||||
room_ids = [str(room.id) for room in rooms]
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/rooms/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()
|
||||
assert content["count"] == 3
|
||||
assert content["next"] == "http://testserver/api/v1.0/rooms/?page=2"
|
||||
assert content["previous"] is None
|
||||
|
||||
assert len(content["results"]) == 2
|
||||
for item in content["results"]:
|
||||
room_ids.remove(item["id"])
|
||||
|
||||
# Get page 2
|
||||
response = client.get(
|
||||
"/api/v1.0/rooms/?page=2",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()
|
||||
|
||||
assert content["count"] == 3
|
||||
assert content["next"] is None
|
||||
assert content["previous"], "http://testserver/api/v1.0/rooms/"
|
||||
|
||||
assert len(content["results"]) == 1
|
||||
room_ids.remove(content["results"][0]["id"])
|
||||
assert room_ids == []
|
||||
|
||||
|
||||
def test_api_rooms_list_authenticated_distinct():
|
||||
"""A public room with several related users should only be listed once."""
|
||||
user = UserFactory()
|
||||
other_user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(is_public=True, users=[user, other_user])
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/rooms/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()
|
||||
assert len(content["results"]) == 1
|
||||
assert content["results"][0]["id"] == str(room.id)
|
||||
344
src/backend/core/tests/rooms/test_api_rooms_retrieve.py
Normal file
344
src/backend/core/tests/rooms/test_api_rooms_retrieve.py
Normal file
@@ -0,0 +1,344 @@
|
||||
"""
|
||||
Test rooms API endpoints in the impress core app: retrieve.
|
||||
"""
|
||||
import random
|
||||
|
||||
from django.test.utils import override_settings
|
||||
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ...factories import RoomFactory, UserFactory, UserResourceAccessFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_anonymous_private_pk():
|
||||
"""
|
||||
Anonymous users should be allowed to retrieve a private room but should not be
|
||||
given any token.
|
||||
"""
|
||||
room = RoomFactory(is_public=False)
|
||||
client = APIClient()
|
||||
response = client.get(f"/api/v1.0/rooms/{room.id!s}/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": False,
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_anonymous_private_pk_no_dashes():
|
||||
"""It should be possible to get a room by its id stripped of its dashes."""
|
||||
room = RoomFactory(is_public=False)
|
||||
id_no_dashes = str(room.id).replace("-", "")
|
||||
|
||||
client = APIClient()
|
||||
response = client.get(f"/api/v1.0/rooms/{id_no_dashes:s}/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": False,
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_anonymous_private_slug():
|
||||
"""It should be possible to get a room by its slug."""
|
||||
room = RoomFactory(is_public=False)
|
||||
client = APIClient()
|
||||
response = client.get(f"/api/v1.0/rooms/{room.slug!s}/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": False,
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_anonymous_private_slug_not_normalized():
|
||||
"""Getting a room by a slug that is not normalized should work."""
|
||||
room = RoomFactory(name="Réunion", is_public=False)
|
||||
client = APIClient()
|
||||
response = client.get("/api/v1.0/rooms/Réunion/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": False,
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
|
||||
@override_settings(ALLOW_UNREGISTERED_ROOMS=True)
|
||||
def test_api_rooms_retrieve_anonymous_unregistered_allowed():
|
||||
"""
|
||||
Retrieving an unregistered room should return a Livekit token
|
||||
if unregistered rooms are allowed.
|
||||
"""
|
||||
client = APIClient()
|
||||
response = client.get("/api/v1.0/rooms/unregistered-room/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": None,
|
||||
"livekit": {
|
||||
"room": "unregistered-room",
|
||||
"token": "foo",
|
||||
},
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
|
||||
|
||||
@override_settings(ALLOW_UNREGISTERED_ROOMS=True)
|
||||
def test_api_rooms_retrieve_anonymous_unregistered_allowed_not_normalized():
|
||||
"""
|
||||
Getting an unregistered room by a slug that is not normalized should work
|
||||
and use the Livekit room on the url-safe name.
|
||||
"""
|
||||
client = APIClient()
|
||||
response = client.get("/api/v1.0/rooms/Réunion/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": None,
|
||||
"livekit": {
|
||||
"room": "reunion",
|
||||
"token": "foo",
|
||||
},
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
|
||||
|
||||
@override_settings(ALLOW_UNREGISTERED_ROOMS=False)
|
||||
def test_api_rooms_retrieve_anonymous_unregistered_not_allowed():
|
||||
"""
|
||||
Retrieving an unregistered room should return a 404 if unregistered rooms are not allowed.
|
||||
"""
|
||||
client = APIClient()
|
||||
response = client.get("/api/v1.0/rooms/unregistered-room/")
|
||||
|
||||
assert response.status_code == 404
|
||||
assert response.json() == {"detail": "Not found."}
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_anonymous_public():
|
||||
"""
|
||||
Anonymous users should be able to retrieve a room with a token provided it is public.
|
||||
"""
|
||||
room = RoomFactory(is_public=True)
|
||||
client = APIClient()
|
||||
response = client.get(f"/api/v1.0/rooms/{room.id!s}/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": True,
|
||||
"livekit": {
|
||||
"room": "foo",
|
||||
"token": "foo",
|
||||
},
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_authenticated_public():
|
||||
"""
|
||||
Authenticated users should be allowed to retrieve a room and get a token for a room to
|
||||
which they are not related, provided the room is public.
|
||||
They should not see related users.
|
||||
"""
|
||||
room = RoomFactory(is_public=True)
|
||||
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": True,
|
||||
"livekit": {
|
||||
"room": "foo",
|
||||
"token": "foo",
|
||||
},
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_authenticated():
|
||||
"""
|
||||
Authenticated users should be allowed to retrieve a private room to which they
|
||||
are not related but should not be given any token.
|
||||
"""
|
||||
room = RoomFactory(is_public=False)
|
||||
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
assert response.json() == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": False,
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_members(django_assert_num_queries):
|
||||
"""
|
||||
Users who are members of a room should be allowed to see related users.
|
||||
"""
|
||||
user = UserFactory()
|
||||
other_user = UserFactory()
|
||||
|
||||
room = RoomFactory()
|
||||
user_access = UserResourceAccessFactory(resource=room, user=user, role="member")
|
||||
other_user_access = UserResourceAccessFactory(
|
||||
resource=room, user=other_user, role="member"
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
with django_assert_num_queries(4):
|
||||
response = client.get(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
content_dict = response.json()
|
||||
|
||||
assert sorted(content_dict.pop("accesses"), key=lambda x: x["id"]) == sorted(
|
||||
[
|
||||
{
|
||||
"id": str(user_access.id),
|
||||
"user": {
|
||||
"id": str(user_access.user.id),
|
||||
"email": user_access.user.email,
|
||||
},
|
||||
"resource": str(room.id),
|
||||
"role": user_access.role,
|
||||
},
|
||||
{
|
||||
"id": str(other_user_access.id),
|
||||
"user": {
|
||||
"id": str(other_user_access.user.id),
|
||||
"email": other_user_access.user.email,
|
||||
},
|
||||
"resource": str(room.id),
|
||||
"role": other_user_access.role,
|
||||
},
|
||||
],
|
||||
key=lambda x: x["id"],
|
||||
)
|
||||
|
||||
assert content_dict == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": False,
|
||||
"is_public": room.is_public,
|
||||
"livekit": {
|
||||
"room": "foo",
|
||||
"token": "foo",
|
||||
},
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_administrators(django_assert_num_queries):
|
||||
"""
|
||||
A user who is an administrator or owner of a room should be allowed
|
||||
to see related users.
|
||||
"""
|
||||
user = UserFactory()
|
||||
other_user = UserFactory()
|
||||
room = RoomFactory()
|
||||
user_access = UserResourceAccessFactory(
|
||||
resource=room, user=user, role=random.choice(["administrator", "owner"])
|
||||
)
|
||||
other_user_access = UserResourceAccessFactory(
|
||||
resource=room, user=other_user, role="member"
|
||||
)
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
with django_assert_num_queries(4):
|
||||
response = client.get(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
content_dict = response.json()
|
||||
|
||||
assert sorted(content_dict.pop("accesses"), key=lambda x: x["id"]) == sorted(
|
||||
[
|
||||
{
|
||||
"id": str(other_user_access.id),
|
||||
"user": {
|
||||
"id": str(other_user_access.user.id),
|
||||
"email": other_user_access.user.email,
|
||||
},
|
||||
"resource": str(room.id),
|
||||
"role": other_user_access.role,
|
||||
},
|
||||
{
|
||||
"id": str(user_access.id),
|
||||
"user": {
|
||||
"id": str(user_access.user.id),
|
||||
"email": user_access.user.email,
|
||||
},
|
||||
"resource": str(room.id),
|
||||
"role": user_access.role,
|
||||
},
|
||||
],
|
||||
key=lambda x: x["id"],
|
||||
)
|
||||
|
||||
assert content_dict == {
|
||||
"id": str(room.id),
|
||||
"is_administrable": True,
|
||||
"is_public": room.is_public,
|
||||
"configuration": {},
|
||||
"livekit": {
|
||||
"room": "foo",
|
||||
"token": "foo",
|
||||
},
|
||||
"name": room.name,
|
||||
"slug": room.slug,
|
||||
}
|
||||
|
||||
# todo - assert generate_token has been called
|
||||
123
src/backend/core/tests/rooms/test_api_rooms_update.py
Normal file
123
src/backend/core/tests/rooms/test_api_rooms_update.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
Test rooms API endpoints in the impress core app: update.
|
||||
"""
|
||||
import random
|
||||
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ...factories import RoomFactory, UserFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_rooms_update_anonymous():
|
||||
"""Anonymous users should not be allowed to update a room."""
|
||||
room = RoomFactory(name="Old name")
|
||||
client = APIClient()
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
{
|
||||
"name": "New name",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
room.refresh_from_db()
|
||||
assert room.name == "Old name"
|
||||
assert room.slug == "old-name"
|
||||
|
||||
|
||||
def test_api_rooms_update_authenticated():
|
||||
"""Authenticated users should not be allowed to update a room."""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(name="Old name")
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
{
|
||||
"name": "New name",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 403
|
||||
room.refresh_from_db()
|
||||
assert room.name == "Old name"
|
||||
assert room.slug == "old-name"
|
||||
|
||||
|
||||
def test_api_rooms_update_members():
|
||||
"""
|
||||
Users who are members of a room but not administrators should
|
||||
not be allowed to update it.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(name="Old name", users=[(user, "member")])
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
new_is_public = not room.is_public
|
||||
response = client.put(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
{
|
||||
"name": "New name",
|
||||
"slug": "should-be-ignored",
|
||||
"is_public": new_is_public,
|
||||
"configuration": {"the_key": "the_value"},
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code, 403
|
||||
room.refresh_from_db()
|
||||
assert room.name == "Old name"
|
||||
assert room.slug == "old-name"
|
||||
assert room.is_public != new_is_public
|
||||
assert room.configuration == {}
|
||||
|
||||
|
||||
def test_api_rooms_update_administrators():
|
||||
"""Administrators or owners of a room should be allowed to update it."""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, random.choice(["administrator", "owner"]))])
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
new_is_public = not room.is_public
|
||||
response = client.put(
|
||||
f"/api/v1.0/rooms/{room.id!s}/",
|
||||
{
|
||||
"name": "New name",
|
||||
"slug": "should-be-ignored",
|
||||
"is_public": new_is_public,
|
||||
"configuration": {"the_key": "the_value"},
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
room.refresh_from_db()
|
||||
assert room.name == "New name"
|
||||
assert room.slug == "new-name"
|
||||
assert room.is_public == new_is_public
|
||||
assert room.configuration == {"the_key": "the_value"}
|
||||
|
||||
|
||||
def test_api_rooms_update_administrators_of_another():
|
||||
"""
|
||||
Being administrator or owner of a room should not grant authorization to update
|
||||
another room.
|
||||
"""
|
||||
user = UserFactory()
|
||||
RoomFactory(users=[(user, random.choice(["administrator", "owner"]))])
|
||||
other_room = RoomFactory(name="Old name")
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/rooms/{other_room.id!s}/",
|
||||
{"name": "New name", "slug": "should-be-ignored"},
|
||||
)
|
||||
assert response.status_code, 403
|
||||
other_room.refresh_from_db()
|
||||
assert other_room.name == "Old name"
|
||||
assert other_room.slug == "old-name"
|
||||
953
src/backend/core/tests/test_api_resource_accesses.py
Normal file
953
src/backend/core/tests/test_api_resource_accesses.py
Normal file
@@ -0,0 +1,953 @@
|
||||
"""
|
||||
Test resource accesses API endpoints in the impress core app.
|
||||
"""
|
||||
import random
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from ..api.serializers import ResourceAccessSerializer
|
||||
from ..factories import (
|
||||
RoomFactory,
|
||||
UserFactory,
|
||||
UserResourceAccessFactory,
|
||||
)
|
||||
from ..models import ResourceAccess, RoleChoices
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_room_user_accesses_list_anonymous():
|
||||
"""Anonymous users should not be allowed to list room user accesses."""
|
||||
|
||||
UserResourceAccessFactory()
|
||||
client = APIClient()
|
||||
|
||||
response = client.get("/api/v1.0/resource-accesses/")
|
||||
assert response.status_code == 401
|
||||
assert response.json() == {
|
||||
"detail": "Authentication credentials were not provided."
|
||||
}
|
||||
|
||||
|
||||
def test_api_room_user_accesses_list_authenticated_not_related():
|
||||
"""
|
||||
Authenticated users should not be allowed to list room user accesses for a room
|
||||
to which they are not related, be it public or private.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
public_room = RoomFactory(is_public=True)
|
||||
UserResourceAccessFactory(resource=public_room)
|
||||
UserResourceAccessFactory(resource=public_room, role="member")
|
||||
UserResourceAccessFactory(resource=public_room, role="administrator")
|
||||
UserResourceAccessFactory(resource=public_room, role="owner")
|
||||
|
||||
private_room = RoomFactory(is_public=False)
|
||||
UserResourceAccessFactory(resource=private_room)
|
||||
UserResourceAccessFactory(resource=private_room, role="member")
|
||||
UserResourceAccessFactory(resource=private_room, role="administrator")
|
||||
UserResourceAccessFactory(resource=private_room, role="owner")
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["results"] == []
|
||||
|
||||
|
||||
def test_api_room_user_accesses_list_authenticated_member():
|
||||
"""
|
||||
Authenticated users should not be allowed to list room user accesses for a room
|
||||
in which they are a simple member.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
public_room = RoomFactory(is_public=True, users=[(user, "member")])
|
||||
UserResourceAccessFactory(resource=public_room)
|
||||
UserResourceAccessFactory(resource=public_room, role="member")
|
||||
UserResourceAccessFactory(resource=public_room, role="administrator")
|
||||
UserResourceAccessFactory(resource=public_room, role="owner")
|
||||
|
||||
private_room = RoomFactory(is_public=False, users=[(user, "member")])
|
||||
UserResourceAccessFactory(resource=private_room)
|
||||
UserResourceAccessFactory(resource=private_room, role="member")
|
||||
UserResourceAccessFactory(resource=private_room, role="administrator")
|
||||
UserResourceAccessFactory(resource=private_room, role="owner")
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["results"] == []
|
||||
|
||||
|
||||
def test_api_room_user_accesses_list_authenticated_administrator():
|
||||
"""
|
||||
Authenticated users should be allowed to list room user accesses for a room
|
||||
in which they are an administrator.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
public_room = RoomFactory(is_public=True)
|
||||
public_room_accesses = (
|
||||
# Access for the logged-in user
|
||||
UserResourceAccessFactory(
|
||||
resource=public_room, user=user, role="administrator"
|
||||
),
|
||||
# Accesses for other users
|
||||
UserResourceAccessFactory(resource=public_room),
|
||||
UserResourceAccessFactory(resource=public_room, role="member"),
|
||||
UserResourceAccessFactory(resource=public_room, role="administrator"),
|
||||
UserResourceAccessFactory(resource=public_room, role="owner"),
|
||||
)
|
||||
|
||||
private_room = RoomFactory(is_public=False)
|
||||
private_room_accesses = (
|
||||
# Access for the logged-in user
|
||||
UserResourceAccessFactory(
|
||||
resource=private_room, user=user, role="administrator"
|
||||
),
|
||||
# Accesses for other users
|
||||
UserResourceAccessFactory(resource=private_room),
|
||||
UserResourceAccessFactory(resource=private_room, role="member"),
|
||||
UserResourceAccessFactory(resource=private_room, role="administrator"),
|
||||
UserResourceAccessFactory(resource=private_room, role="owner"),
|
||||
)
|
||||
response = client.get(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
results = response.json()["results"]
|
||||
assert len(results) == 10
|
||||
assert [item["id"] for item in results].sort() == [
|
||||
str(access.id) for access in public_room_accesses + private_room_accesses
|
||||
].sort()
|
||||
|
||||
|
||||
def test_api_room_user_accesses_list_authenticated_owner():
|
||||
"""
|
||||
Authenticated users should be allowed to list room user accesses for a room
|
||||
in which they are owner.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
public_room = RoomFactory(is_public=True)
|
||||
public_room_accesses = (
|
||||
# Access for the logged-in user
|
||||
UserResourceAccessFactory(resource=public_room, user=user, role="owner"),
|
||||
# Accesses for other users
|
||||
UserResourceAccessFactory(resource=public_room),
|
||||
UserResourceAccessFactory(resource=public_room, role="member"),
|
||||
UserResourceAccessFactory(resource=public_room, role="administrator"),
|
||||
UserResourceAccessFactory(resource=public_room, role="owner"),
|
||||
)
|
||||
private_room = RoomFactory(is_public=False)
|
||||
private_room_accesses = (
|
||||
# Access for the logged-in user
|
||||
UserResourceAccessFactory(resource=private_room, user=user, role="owner"),
|
||||
# Accesses for other users
|
||||
UserResourceAccessFactory(resource=private_room),
|
||||
UserResourceAccessFactory(resource=private_room, role="member"),
|
||||
UserResourceAccessFactory(resource=private_room, role="administrator"),
|
||||
UserResourceAccessFactory(resource=private_room, role="owner"),
|
||||
)
|
||||
response = client.get("/api/v1.0/resource-accesses/")
|
||||
assert response.status_code == 200
|
||||
results = response.json()["results"]
|
||||
assert len(results) == 10
|
||||
assert [item["id"] for item in results].sort() == [
|
||||
str(access.id) for access in public_room_accesses + private_room_accesses
|
||||
].sort()
|
||||
|
||||
|
||||
@mock.patch.object(PageNumberPagination, "get_page_size", return_value=2)
|
||||
def test_api_room_user_accesses_list_pagination(_mock_page_size):
|
||||
"""Pagination should work as expected."""
|
||||
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory()
|
||||
accesses = [
|
||||
UserResourceAccessFactory(
|
||||
resource=room, user=user, role=random.choice(["administrator", "owner"])
|
||||
),
|
||||
*UserResourceAccessFactory.create_batch(2, resource=room),
|
||||
]
|
||||
access_ids = [str(access.id) for access in accesses]
|
||||
|
||||
response = client.get(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
content = response.json()
|
||||
|
||||
assert content["count"] == 3
|
||||
assert content["next"] == "http://testserver/api/v1.0/resource-accesses/?page=2"
|
||||
assert content["previous"] is None
|
||||
|
||||
assert len(content["results"]) == 2
|
||||
for item in content["results"]:
|
||||
access_ids.remove(item["id"])
|
||||
|
||||
# Get page 2
|
||||
response = client.get("/api/v1.0/resource-accesses/?page=2")
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.json()
|
||||
|
||||
assert content["count"] == 3
|
||||
assert content["next"] is None
|
||||
assert content["previous"] == "http://testserver/api/v1.0/resource-accesses/"
|
||||
assert len(content["results"]) == 1
|
||||
access_ids.remove(content["results"][0]["id"])
|
||||
assert access_ids == []
|
||||
|
||||
|
||||
# Retrieve
|
||||
|
||||
|
||||
def test_api_room_user_accesses_retrieve_anonymous():
|
||||
"""
|
||||
Anonymous users should not be allowed to retrieve a room user access.
|
||||
"""
|
||||
access = UserResourceAccessFactory()
|
||||
client = APIClient()
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.json() == {
|
||||
"detail": "Authentication credentials were not provided."
|
||||
}
|
||||
|
||||
|
||||
def test_api_room_user_accesses_retrieve_authenticated_not_related():
|
||||
"""
|
||||
Authenticated users should not be allowed to retrieve a room user access for
|
||||
a room to which they are not related, be it public or private.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
for is_public in [True, False]:
|
||||
room = RoomFactory(is_public=is_public)
|
||||
assert len(RoleChoices.choices) == 3
|
||||
|
||||
for role, _name in RoleChoices.choices:
|
||||
access = UserResourceAccessFactory(resource=room, role=role)
|
||||
response = client.get(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert response.json() == {
|
||||
"detail": "You do not have permission to perform this action."
|
||||
}
|
||||
|
||||
|
||||
def test_api_room_user_accesses_retrieve_authenticated_member():
|
||||
"""
|
||||
Authenticated users should not be allowed to retrieve a room user access for a room in
|
||||
which they are a simple member, be it public or private.
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
for is_public in [True, False]:
|
||||
room = RoomFactory(
|
||||
is_public=is_public,
|
||||
users=[(user, "member")],
|
||||
)
|
||||
assert len(RoleChoices.choices) == 3
|
||||
|
||||
for role, _name in RoleChoices.choices:
|
||||
access = UserResourceAccessFactory(resource=room, role=role)
|
||||
response = client.get(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert response.json() == {
|
||||
"detail": "You do not have permission to perform this action."
|
||||
}
|
||||
|
||||
|
||||
def test_api_room_user_accesses_retrieve_authenticated_administrator():
|
||||
"""
|
||||
A user who is an administrator of a room should be allowed to retrieve the
|
||||
associated room user accesses
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
for is_public in [True, False]:
|
||||
room = RoomFactory(is_public=is_public, users=[(user, "administrator")])
|
||||
assert len(RoleChoices.choices) == 3
|
||||
|
||||
for role, _name in RoleChoices.choices:
|
||||
access = UserResourceAccessFactory(resource=room, role=role)
|
||||
response = client.get(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(access.id),
|
||||
"user": str(access.user.id),
|
||||
"resource": str(access.resource_id),
|
||||
"role": access.role,
|
||||
}
|
||||
|
||||
|
||||
def test_api_room_user_accesses_retrieve_authenticated_owner():
|
||||
"""
|
||||
A user who is an owner of a room should be allowed to retrieve the
|
||||
associated room user accesses
|
||||
"""
|
||||
user = UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
for is_public in [True, False]:
|
||||
room = RoomFactory(is_public=is_public, users=[(user, "owner")])
|
||||
assert len(RoleChoices.choices) == 3
|
||||
|
||||
for role, _name in RoleChoices.choices:
|
||||
access = UserResourceAccessFactory(resource=room, role=role)
|
||||
response = client.get(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"id": str(access.id),
|
||||
"user": str(access.user.id),
|
||||
"resource": str(access.resource_id),
|
||||
"role": access.role,
|
||||
}
|
||||
|
||||
|
||||
# Create
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_anonymous():
|
||||
"""Anonymous users should not be allowed to create room user accesses."""
|
||||
user = UserFactory()
|
||||
room = RoomFactory()
|
||||
|
||||
client = APIClient()
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(user.id),
|
||||
"resource": str(room.id),
|
||||
"role": random.choice(["member", "administrator", "owner"]),
|
||||
},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
assert response.json() == {
|
||||
"detail": "Authentication credentials were not provided."
|
||||
}
|
||||
assert ResourceAccess.objects.exists() is False
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_authenticated():
|
||||
"""Authenticated users should not be allowed to create room user accesses."""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
room = RoomFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(other_user.id),
|
||||
"resource": str(room.id),
|
||||
"role": random.choice(["member", "administrator", "owner"]),
|
||||
},
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert response.json() == {
|
||||
"detail": "You must be administrator or owner of a room to add accesses to it."
|
||||
}
|
||||
assert ResourceAccess.objects.filter(user=other_user).exists() is False
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_members():
|
||||
"""
|
||||
A user who is a simple member in a room should not be allowed to create
|
||||
room user accesses in this room.
|
||||
"""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
room = RoomFactory(users=[(user, "member")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(other_user.id),
|
||||
"resource": str(room.id),
|
||||
"role": random.choice(["member", "administrator", "owner"]),
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert response.json() == {
|
||||
"detail": "You must be administrator or owner of a room to add accesses to it."
|
||||
}
|
||||
assert ResourceAccess.objects.filter(user=other_user).exists() is False
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_administrators_except_owner():
|
||||
"""
|
||||
A user who is administrator in a room should be allowed to create
|
||||
room user accesses in this room for roles other than owner (which is tested in the
|
||||
subsequent test).
|
||||
"""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(other_user.id),
|
||||
"resource": str(room.id),
|
||||
"role": random.choice(["member", "administrator"]),
|
||||
},
|
||||
)
|
||||
assert response.status_code == 201
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
assert ResourceAccess.objects.filter(user=other_user).exists() is True
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_administrators_owner():
|
||||
"""
|
||||
A user who is administrator in a room should not be allowed to create room
|
||||
user accesses in this room for the owner role.
|
||||
"""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(other_user.id),
|
||||
"resource": str(room.id),
|
||||
"role": "owner",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert ResourceAccess.objects.filter(user=other_user).exists() is False
|
||||
|
||||
|
||||
def test_api_room_user_accesses_create_owner_all_roles():
|
||||
"""
|
||||
A user who is owner in a room should be allowed to create
|
||||
room user accesses in this room for all roles.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
for i, role in enumerate(["member", "administrator", "owner"]):
|
||||
other_user = UserFactory()
|
||||
response = client.post(
|
||||
"/api/v1.0/resource-accesses/",
|
||||
{
|
||||
"user": str(other_user.id),
|
||||
"resource": str(room.id),
|
||||
"role": role,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert ResourceAccess.objects.count() == i + 2
|
||||
assert ResourceAccess.objects.filter(user=other_user).exists() is True
|
||||
|
||||
|
||||
# Update
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_anonymous():
|
||||
"""Anonymous users should not be allowed to update a room user access."""
|
||||
access = UserResourceAccessFactory()
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
client = APIClient()
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory().id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 401
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_authenticated():
|
||||
"""Authenticated users should not be allowed to update a room user access."""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
access = UserResourceAccessFactory()
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "member")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_member():
|
||||
"""
|
||||
A user who is a simple member in a room should not be allowed to update
|
||||
a user access for this room.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "member")])
|
||||
access = UserResourceAccessFactory(resource=room)
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "member")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_administrator_except_owner():
|
||||
"""
|
||||
A user who is an administrator in a room should be allowed to update
|
||||
a user access for this room, as long as she does not try to set the role to owner.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
access = UserResourceAccessFactory(
|
||||
resource=room, role=random.choice(["member", "administrator"])
|
||||
)
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "administrator")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(["member", "administrator"]),
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code, 200
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
if field == "role":
|
||||
assert updated_values == {**old_values, "role": new_values["role"]}
|
||||
else:
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_administrator_from_owner():
|
||||
"""
|
||||
A user who is an administrator in a room, should not be allowed to update
|
||||
the user access of an owner for this room.
|
||||
"""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
access = UserResourceAccessFactory(resource=room, user=other_user, role="owner")
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "administrator")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_administrator_to_owner():
|
||||
"""
|
||||
A user who is an administrator in a room should not be allowed to update
|
||||
the user access of another user when granting ownership.
|
||||
"""
|
||||
user, other_user = UserFactory.create_batch(2)
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
access = UserResourceAccessFactory(
|
||||
resource=room,
|
||||
user=other_user,
|
||||
role=random.choice(["member", "administrator"]),
|
||||
)
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "administrator")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": "owner",
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
if field == "role":
|
||||
assert response.status_code == 403
|
||||
else:
|
||||
assert response.status_code == 200
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_owner_except_owner():
|
||||
"""
|
||||
A user who is an owner in a room should be allowed to update
|
||||
a user access for this room except for existing owner accesses.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
access = UserResourceAccessFactory(
|
||||
resource=room, role=random.choice(["member", "administrator"])
|
||||
)
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "administrator")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
if field == "role":
|
||||
assert updated_values == {**old_values, "role": new_values["role"]}
|
||||
else:
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_owner_for_owners():
|
||||
"""
|
||||
A user who is an owner in a room should not be allowed to update
|
||||
an existing owner user access for this room.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
access = UserResourceAccessFactory(resource=room, role="owner")
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
|
||||
new_values = {
|
||||
"id": uuid4(),
|
||||
"resource": RoomFactory(users=[(user, "administrator")]).id,
|
||||
"user": UserFactory().id,
|
||||
"role": random.choice(RoleChoices.choices)[0],
|
||||
}
|
||||
for field, value in new_values.items():
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, field: value},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 403
|
||||
access.refresh_from_db()
|
||||
updated_values = ResourceAccessSerializer(instance=access).data
|
||||
assert updated_values == old_values
|
||||
|
||||
|
||||
def test_api_room_user_accesses_update_owner_self():
|
||||
"""
|
||||
A user who is an owner in a room should be allowed to update
|
||||
her own user access provided there are other owners in the room.
|
||||
"""
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
room = RoomFactory()
|
||||
access = UserResourceAccessFactory(resource=room, user=user, role="owner")
|
||||
old_values = ResourceAccessSerializer(instance=access).data
|
||||
new_role = random.choice(["member", "administrator"])
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, "role": new_role},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
access.refresh_from_db()
|
||||
assert access.role == "owner"
|
||||
|
||||
# Add another owner and it should now work
|
||||
UserResourceAccessFactory(resource=room, role="owner")
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
{**old_values, "role": new_role},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
access.refresh_from_db()
|
||||
assert access.role == new_role
|
||||
|
||||
|
||||
# Delete
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_anonymous():
|
||||
"""Anonymous users should not be allowed to destroy a room user access."""
|
||||
access = UserResourceAccessFactory()
|
||||
client = APIClient()
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_authenticated():
|
||||
"""
|
||||
Authenticated users should not be allowed to delete a room user access for a room in
|
||||
which they are not administrator.
|
||||
"""
|
||||
access = UserResourceAccessFactory()
|
||||
user = UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_members():
|
||||
"""
|
||||
Authenticated users should not be allowed to delete a room user access for a room in
|
||||
which they are a simple member.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "member")])
|
||||
access = UserResourceAccessFactory(resource=room)
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
assert ResourceAccess.objects.filter(user=access.user).exists() is True
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_administrators():
|
||||
"""
|
||||
Users who are administrators in a room should be allowed to delete a user access
|
||||
from the room provided it is not ownership.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "administrator")])
|
||||
access = UserResourceAccessFactory(
|
||||
resource=room, role=random.choice(["member", "administrator"])
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
assert ResourceAccess.objects.filter(user=access.user).exists() is True
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 204
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_owners_except_owners():
|
||||
"""
|
||||
Users should be able to delete the room user access of another user
|
||||
for a room in which they are owner except for owners.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
access = UserResourceAccessFactory(
|
||||
resource=room, role=random.choice(["member", "administrator"])
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
assert ResourceAccess.objects.filter(user=access.user).exists() is True
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 204
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_owners_for_owners():
|
||||
"""
|
||||
Users should not be able to delete the room user access of another owner
|
||||
even for a room in which they are owners.
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, "owner")])
|
||||
access = UserResourceAccessFactory(resource=room, role="owner")
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
assert ResourceAccess.objects.filter(user=access.user).exists() is True
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert ResourceAccess.objects.count() == 2
|
||||
|
||||
|
||||
def test_api_room_user_access_delete_owners_last_owner():
|
||||
"""
|
||||
It should not be possible to delete the last owner access from a room
|
||||
"""
|
||||
user = UserFactory()
|
||||
room = RoomFactory()
|
||||
access = UserResourceAccessFactory(resource=room, user=user, role="owner")
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
response = client.delete(
|
||||
f"/api/v1.0/resource-accesses/{access.id!s}/",
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert ResourceAccess.objects.count() == 1
|
||||
@@ -10,6 +10,10 @@ from core.authentication.urls import urlpatterns as oidc_urls
|
||||
# - Main endpoints
|
||||
router = DefaultRouter()
|
||||
router.register("users", viewsets.UserViewSet, basename="users")
|
||||
router.register("rooms", viewsets.RoomViewSet, basename="rooms")
|
||||
router.register(
|
||||
"resource-accesses", viewsets.ResourceAccessViewSet, basename="resource_accesses"
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
|
||||
@@ -372,6 +372,9 @@ class Base(Configuration):
|
||||
DEFAULT_ROOM_IS_PUBLIC = values.BooleanValue(
|
||||
True, environ_name="MAGNIFY_DEFAULT_ROOM_IS_PUBLIC", environ_prefix=None
|
||||
)
|
||||
ALLOW_UNREGISTERED_ROOMS = values.BooleanValue(
|
||||
True, environ_name="MAGNIFY_ALLOW_UNREGISTERED_ROOMS", environ_prefix=None
|
||||
)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user