(project) add Room, Ressource, Access models from Magnify

I picked few models from Magnify to build our MVP:

- Resource:
   A generic model representing any type of resource. Though currently used only by Room,
   it encapsulates a meaningful business logic as an abstract model.
- Room:
   The primary object we manipulate, representing a meeting room with access
   and permission controls.
- ResourceAccess
   Ensures relevant users have the appropriate permissions for a given room.

** What’s different from Magnify ? **

Removed group logic; it will be added later. For now, we rely on the user model's
property to get its groups via desk.

Removed any logic or method related to Jitsi or LiveKit. These servers will be integrated
in the upcomming commits.

Focus on Room-related models to maintain a minimal and functional product (KISS principle)
until we achieve product-market fit (PMF).

Creating simple public and private, permanent and temporary rooms
is sufficient for building our MVP.

The Meeting model in Magnify, which supports recurrence, should be handled by
the collaborative calendar instead.

Adapted the unit test to use Pytest, and linted all the sources using Ruff linter.

(Migrations will be squashed before releasing the MVP)
This commit is contained in:
lebaudantoine
2024-06-24 19:14:27 +02:00
parent fbe79b7b2b
commit 2e6feede31
6 changed files with 565 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
"""
Unit tests for the ResourceAccess model with user
"""
from django.core.exceptions import ValidationError
import pytest
from core.factories import RoomFactory, UserResourceAccessFactory
pytestmark = pytest.mark.django_db
def test_models_resource_accesses_user_str_member_room():
"""The str representation should consist in the room and usernames."""
room = RoomFactory(name="my room")
access = UserResourceAccessFactory(
resource=room, user__email="john.doe@impress.com", role="member"
)
assert str(access) == "Member role for john.doe@impress.com on my room"
def test_models_resource_accesses_user_str_member_resource():
"""The str representation should consist in the resource id and username."""
access = UserResourceAccessFactory(
user__email="john.doe@impress.com", role="member"
)
assert (
str(access)
== f"Member role for john.doe@impress.com on resource {access.resource_id!s}"
)
def test_models_resource_accesses_user_str_admin():
"""The str representation for an admin user should include the role."""
access = UserResourceAccessFactory(
user__email="john.doe@impress.com", role="administrator"
)
assert (
str(access)
== f"Administrator role for john.doe@impress.com on resource {access.resource_id!s}"
)
def test_models_resource_accesses_user_str_owner():
"""The str representation for an admin user should include the role."""
access = UserResourceAccessFactory(user__email="john.doe@impress.com", role="owner")
assert (
str(access)
== f"Owner role for john.doe@impress.com on resource {access.resource_id!s}"
)
def test_models_resource_accesses_user_unique():
"""Room user accesses should be unique."""
access = UserResourceAccessFactory()
with pytest.raises(ValidationError) as excinfo:
UserResourceAccessFactory(user=access.user, resource=access.resource)
assert "Resource access with this User and Resource already exists." in str(
excinfo.value
)

View File

@@ -0,0 +1,165 @@
"""
Unit tests for the Room model
"""
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ValidationError
import pytest
from core.factories import RoomFactory, UserFactory
from core.models import Room
pytestmark = pytest.mark.django_db
def test_models_rooms_str():
"""The str representation should be the name."""
room = RoomFactory()
assert str(room) == room.name
def test_models_rooms_ordering():
"""Rooms should be returned ordered by name."""
RoomFactory.create_batch(3)
rooms = Room.objects.all()
# Remove hyphens because postgresql is ignoring them when they sort
assert rooms[1].name.replace("-", "") >= rooms[0].name.replace("-", "")
assert rooms[2].name.replace("-", "") >= rooms[1].name.replace("-", "")
def test_models_rooms_name_maxlength():
"""The name field should be less than 100 characters."""
RoomFactory(name="a" * 100)
with pytest.raises(ValidationError) as excinfo:
RoomFactory(name="a" * 101)
assert "Ensure this value has at most 100 characters (it has 101)." in str(
excinfo.value
)
def test_models_rooms_slug_unique():
"""Room slugs should be unique."""
RoomFactory(name="a room!")
with pytest.raises(ValidationError) as excinfo:
RoomFactory(name="A Room!")
assert "Room with this Slug already exists." in str(excinfo.value)
def test_models_rooms_name_slug_like_uuid():
"""
It should raise an error if the value of the name field leads to a slug looking
like a UUID . We need unicity on the union of the `id` and `slug` fields.
"""
with pytest.raises(ValidationError) as excinfo:
RoomFactory(name="918689fb-038e 4e81-bf09 efd5902c5f0b")
assert 'Room name "918689fb-038e 4e81-bf09 efd5902c5f0b" is reserved.' in str(
excinfo.value
)
def test_models_rooms_slug_automatic():
"""Room slugs should be automatically populated upon saving."""
room = Room(name="Eléphant in the room")
room.save()
assert room.slug == "elephant-in-the-room"
def test_models_rooms_users():
"""It should be possible to attach users to a room."""
room = RoomFactory()
user = UserFactory()
room.users.add(user)
room.refresh_from_db()
assert list(room.users.all()) == [user]
def test_models_rooms_is_public_default():
"""A room should be public by default."""
room = Room.objects.create(name="room")
assert room.is_public is True
# Access rights methods
def test_models_rooms_access_rights_none(django_assert_num_queries):
"""Calling access rights methods with None should return None."""
room = RoomFactory()
with django_assert_num_queries(0):
assert room.get_role(None) is None
with django_assert_num_queries(0):
assert room.is_administrator(None) is False
with django_assert_num_queries(0):
assert room.is_owner(None) is False
def test_models_rooms_access_rights_anonymous(django_assert_num_queries):
"""Check access rights methods on the room object for an anonymous user."""
user = AnonymousUser()
room = RoomFactory()
with django_assert_num_queries(0):
assert room.get_role(user) is None
with django_assert_num_queries(0):
assert room.is_administrator(user) is False
with django_assert_num_queries(0):
assert room.is_owner(user) is False
def test_models_rooms_access_rights_authenticated(django_assert_num_queries):
"""Check access rights methods on the room object for an unrelated user."""
user = UserFactory()
room = RoomFactory()
with django_assert_num_queries(1):
assert room.get_role(user) is None
with django_assert_num_queries(1):
assert room.is_administrator(user) is False
with django_assert_num_queries(1):
assert room.is_owner(user) is False
def test_models_rooms_access_rights_member_direct(django_assert_num_queries):
"""Check access rights methods on the room object for a direct member."""
user = UserFactory()
room = RoomFactory(users=[(user, "member")])
with django_assert_num_queries(1):
assert room.get_role(user) == "member"
with django_assert_num_queries(1):
assert room.is_administrator(user) is False
with django_assert_num_queries(1):
assert room.is_owner(user) is False
def test_models_rooms_access_rights_administrator_direct(django_assert_num_queries):
"""The is_administrator method should return True for a direct administrator."""
user = UserFactory()
room = RoomFactory(users=[(user, "administrator")])
with django_assert_num_queries(1):
assert room.get_role(user) == "administrator"
with django_assert_num_queries(1):
assert room.is_administrator(user) is True
with django_assert_num_queries(1):
assert room.is_owner(user) is False
def test_models_rooms_access_rights_owner_direct(django_assert_num_queries):
"""Check access rights methods on the room object for an owner."""
user = UserFactory()
room = RoomFactory(users=[(user, "owner")])
with django_assert_num_queries(1):
assert room.get_role(user) == "owner"
with django_assert_num_queries(1):
assert room.is_administrator(user) is True
with django_assert_num_queries(1):
assert room.is_owner(user) is True