This commit is contained in:
Kilton937342 2022-09-21 22:31:50 +02:00
parent 84b38cc12d
commit a26b4aaa43
7 changed files with 871 additions and 104 deletions

7
backend/api/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"python.testing.pytestArgs": [
"."
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

View File

@ -9,19 +9,20 @@ def create_room_db(*,room: RoomCreate, user: User | None = None, username: str |
id_code = generate_unique_code(Room,s=db)
room_obj = Room(**room.dict(exclude_unset=True), id_code=id_code)
if user is not None:
member = Member(user_id=user.id, room=room_obj)
member = Member(user_id=user.id, room=room_obj, is_admin=True)
db.add(member)
db.commit()
db.refresh(member)
if username is not None:
reconnect_code = generate_unique_code(Anonymous, s=db, field_name='reconnect_code')
anonymous = Anonymous(username=username, reconnect_code=reconnect_code)
member = Member(anonymous=anonymous, room=room_obj)
member = Member(anonymous=anonymous, room=room_obj, is_admin=True)
db.add(member)
db.commit()
db.refresh(member)
if username is None and user is None:
raise ValueError('Username or user required')
return {"room": room_obj, "member": member}
def check_room(room_id: str, db: Session = Depends(get_session)):

View File

@ -1,3 +1,4 @@
from pydantic import root_validator
from typing import List, Optional, TYPE_CHECKING
from sqlmodel import SQLModel, Field, Relationship
@ -48,18 +49,43 @@ class Member(SQLModel, table = True):
is_admin: bool = False
waiting: bool = True
waiting: bool = False
online: bool = False
waiter_code: Optional[str] = Field(default= None)
class RoomRead(RoomBase):
id_code: str
#members: List['Member']
class AnonymousRead(AnonymousBase):
reconnect_code: str
class Username(SQLModel):
username: str
class MemberWithRelations(SQLModel):
is_admin: bool
user: UserRead | None = None
anonymous: AnonymousRead | None = None
class MemberRead(SQLModel):
anonymous: AnonymousRead = None
user: Username = None
username: str
reconnect_code: str = ''
isUser: bool
isAdmin: bool
class MemberSerializer(MemberRead):
member: MemberWithRelations
@root_validator
def parse_member(cls, values):
member = values.get('member')
if member == None:
return values
member_obj = member.user or member.anonymous
if member_obj is None:
raise ValueError('User or anonymous required')
return {"username": member_obj.username, "reconnect_code": getattr(member_obj, "reconnect_code", ""), "isAdmin": member.is_admin, "isUser": member.user != None}

View File

@ -7,7 +7,7 @@ from services.auth import get_current_user_optional, jwt_required
from fastapi.openapi.utils import get_openapi
from database.auth.models import User, UserRead
from database.exercices.models import Exercice, ExerciceRead
from database.room.models import Room, Anonymous, Member
from database.room.models import Room, Anonymous, MemberWithRelations
import database.db
from fastapi_pagination import add_pagination
from fastapi.responses import PlainTextResponse

View File

@ -1,3 +1,9 @@
from pydantic import Field
from pydantic import create_model_from_typeddict
from pydantic.error_wrappers import ValidationError
from pydantic import validate_arguments
from services.database import generate_unique_code
from sqlmodel import col
from sqlmodel import select
from pydantic import BaseModel
from typing import Any, Callable, Dict, List, Optional
@ -8,10 +14,11 @@ from database.auth.models import User
from database.db import get_session
from database.room.crud import check_room, create_room_db, userInRoom
from sqlmodel import Session
from database.room.models import Anonymous, Member, MemberRead, Room, RoomCreate, RoomRead
from database.room.models import Anonymous, MemberSerializer, MemberWithRelations, MemberRead, Room, RoomCreate, RoomRead, Member
from services.auth import get_current_user_optional
from fastapi.exceptions import HTTPException
from jose import jwt, exceptions
import inspect
router = APIRouter(tags=["room"])
@ -20,17 +27,30 @@ class RoomAndMember(BaseModel):
member: MemberRead
class Waiter(BaseModel):
username: str
waiter_id: str
def serialize_member(member: Member) -> MemberRead | Waiter:
member_obj = member.user or member.anonymous
if member.waiting == False:
return MemberRead(username=member_obj.username, reconnect_code=getattr(member_obj, "reconnect_code", ""), isUser=member.user_id != None, isAdmin=member.is_admin)
if member.waiting == True:
return Waiter(username=member_obj.username, waiter_id=member.waiter_code)
@router.post('/room', response_model=RoomAndMember)
def create_room(room: RoomCreate, username: Optional[str] = Query(default=None, max_length=20), user: User | None = Depends(get_current_user_optional), db: Session = Depends(get_session)):
room_obj = create_room_db(room=room, user=user, username=username, db=db)
return room_obj
return {'room': room_obj['room'], "member": serialize_member(room_obj['member'])}
class ConnectionManager:
def __init__(self):
self.active_connections: Dict[str, List[WebSocket]] = {}
async def add(self, group: str, ws: WebSocket):
def add(self, group: str, ws: WebSocket):
if group not in self.active_connections:
self.active_connections[group] = []
@ -49,22 +69,54 @@ class ConnectionManager:
await connection.send_json(message)
manager = ConnectionManager()
def make_event_decorator(eventsDict):
def _(name: str):
def _(name: str, conditions: List[Callable | bool] = []):
def add_event(func):
eventsDict[name] = func
model = validate_arguments(func).model
eventsDict[name] = {"func": func,
"conditions": conditions, "model": model}
return func
return add_event
return _
class Event(BaseModel):
func: Callable
conditions: List[Callable | bool]
model: BaseModel
def dict_model(model: BaseModel, exclude: List[str]):
value = {}
for n, f in model:
if n not in exclude:
value[n] = f
return value
def dict_all(obj: Any):
if isinstance(obj, dict):
value = {}
for k, v in obj.items():
if isinstance(v, dict):
v = dict_all(v)
value[k] = dict(v)
elif isinstance(v, BaseModel):
value[k] = dict(v)
else:
try:
value[k] = dict(v)
except:
value[k] = v
return value
return dict(obj)
class Consumer:
events: Dict[str, Callable] = {}
events: Dict[str, Event] = {}
sendings: Dict[str, Any] = {}
event = make_event_decorator(events)
sending = make_event_decorator(sendings)
def __init__(self, ws: WebSocket):
self.ws: WebSocket = ws
@ -73,13 +125,70 @@ class Consumer:
async def connect(self):
pass
async def validation_error_handler(self, e: ValidationError):
errors = e.errors()
await self.ws.send_json({"type": "error", "data": {"detail": [{ers['loc'][-1]: ers['msg']} for ers in errors]}})
async def send(self, payload):
type = payload.get('type', None)
print('TYPE', type, self.member.id)
if type is not None:
event_wrapper = self.sendings.get(type, None)
if event_wrapper is not None:
handler = event_wrapper.get('func')
conditions = event_wrapper.get('conditions')
is_valid = all([(await c(self)) if inspect.iscoroutinefunction(c) else c(self) if inspect.isfunction(c) else c == True if isinstance(c, bool) else True for c in conditions])
if handler is not None and is_valid:
model = event_wrapper.get("model")
data = payload.get('data') or {}
try:
validated_payload = model(self=self, **data)
except ValidationError as e:
await self.ws.send_json({"type": "error", "data": {"msg": "Oops there was an error"}})
return
validated_payload = dict_model(validated_payload,
exclude=["v__duplicate_kwargs", "args", 'kwargs', "self"])
try:
parsed_payload = handler(
self, **validated_payload)
await self.ws.send_json({'type': type, "data": dict_all(parsed_payload)})
return
except Exception as e:
print('NOPE', self.member.id, e)
return
return
print('pls')
await self.ws.send_json(payload)
print('sent')
async def receive(self, data):
event = data.get('type', None)
if event is not None:
handler = self.events.get(event, None)
if handler is not None:
payload = data.get('data')
await handler(self, payload)
event_wrapper = self.events.get(event, None)
if event_wrapper is not None:
handler = event_wrapper.get('func')
conditions = event_wrapper.get('conditions')
is_valid = all([(await c(self)) if inspect.iscoroutinefunction(c) else c(self) if inspect.isfunction(c) else c == True if isinstance(c, bool) else True for c in conditions])
if handler is not None and is_valid:
model = event_wrapper.get("model")
payload = data.get('data') or {}
try:
validated_payload = model(self=self, **payload)
except ValidationError as e:
await self.validation_error_handler(e)
return
await handler(**{k: v for k, v in validated_payload.dict().items() if k not in ["v__duplicate_kwargs", "args", 'kwargs']})
async def disconnect(self):
pass
@ -94,6 +203,36 @@ class Consumer:
await self.disconnect()
class ConsumerManager:
def __init__(self):
self.active_connections: Dict[str, List[Consumer]] = {}
def add(self, group: str, ws: Consumer):
if group not in self.active_connections:
self.active_connections[group] = []
print("adding", ws, self.active_connections[group])
if ws not in self.active_connections[group]:
print('ACTUALLY ADDING')
self.active_connections[group].append(ws)
def remove(self, group: str, ws: Consumer):
if group in self.active_connections:
if ws in self.active_connections[group]:
self.active_connections[group].remove(ws)
async def broadcast(self, message, group: str, exclude: list[Consumer] = []):
if group in self.active_connections:
print(self.active_connections[group], exclude)
for connection in list(set(self.active_connections[group])):
if connection not in exclude:
print('SEND TO', connection, message)
await connection.send(message)
manager = ConsumerManager()
class Token(BaseModel):
token: str
@ -115,12 +254,30 @@ def get_member_from_user(user_id: int, room_id: int, db: Session):
return member
def get_member_from_token(token: str, room_id: int, db: Session):
user = get_user_from_token(token, db)
if user is False:
return False
if user is None:
return None
member = get_member_from_user(user.id, room_id, db)
return member
def get_member_from_anonymous(anonymous_id: int, room_id: int, db: Session):
member = db.exec(select(Member).where(Member.room_id ==
room_id, Member.anonymous_id == anonymous_id)).first()
return member
def get_member_reconnect_code(reconnect_code: str, room_id: int, db: Session):
anonymous = get_anonymous_from_code(reconnect_code, db)
if anonymous is None:
return None
member = get_member_from_anonymous(anonymous.id, room_id, db)
return member
def get_anonymous_from_code(reconnect_code: str, db: Session):
anonymous = db.exec(select(Anonymous).where(
Anonymous.reconnect_code == reconnect_code)).first()
@ -136,31 +293,117 @@ def connect_member(member: Member, db: Session):
def disconnect_member(member: Member, db: Session):
member.online = False
if member.waiting == False:
member.online = False
db.add(member)
db.commit()
db.refresh(member)
return member
else:
db.delete(member)
db.commit()
return member
def validate_username(username: str, room: Room, db: Session = Depends(get_session)):
print('VALIDATE', username)
if len(username) > 20:
return None
members = select(Member.anonymous_id).where(
Member.room_id == room.id, Member.anonymous_id != None)
anonymous = select(Anonymous).where(
col(Anonymous.id).in_(members), Anonymous.username == username)
username_anonymous = db.exec(anonymous).first()
return None if username_anonymous is not None else username
def create_anonymous_member(username: str, room: Room, db: Session):
username = validate_username(username)
if username is None:
return None
reconnect_code = generate_unique_code(
Anonymous, s=db, field_name="reconnect_code")
anonymous = Anonymous(username=username, reconnect_code=reconnect_code)
member = Member(room=room, anonymous=anonymous)
db.add(member)
db.commit()
db.refresh(member)
return member
def validate_username(username: str, room: Room, db: Session):
members = select(Member).where(Member.room_id == room.id, Member.anonymous_id != None)
def create_anonymous_member(username: str, room: Room, db: Session):
pass
def create_user_member(user: User, room: Room, db: Session):
member = get_member_from_user(user.id, room.id, db)
if member is not None:
return None
member = Member(room=room, user=user)
db.add(member)
db.commit()
db.refresh(member)
return member
def create_anonymous_waiter(username: str, room: Room, db: Session):
username = validate_username(username, room, db)
if username is None:
return None
reconnect_code = generate_unique_code(
Anonymous, s=db, field_name="reconnect_code")
anonymous = Anonymous(username=username, reconnect_code=reconnect_code)
waiter_code = generate_unique_code(Member, s=db, field_name="waiter_code")
member = Member(room=room, anonymous=anonymous,
waiting=True, waiter_code=waiter_code)
db.add(member)
db.commit()
db.refresh(member)
return member
def create_user_waiter(user: User, room: Room, db: Session):
member = get_member_from_user(user.id, room.id, db)
if member is not None:
return None
waiter_code = generate_unique_code(Member, s=db, field_name="waiter_code")
member = Member(room=room, user=user, waiting=True,
waiter_code=waiter_code)
db.add(member)
db.commit()
db.refresh(member)
return member
def get_waiter(waiter_code: str, db: Session):
return db.exec(select(Member).where(Member.waiter_code == waiter_code)).first()
def accept_waiter(member: Member, db: Session):
member.waiting = False
member.waiter_code = None
db.add(member)
db.commit()
db.refresh(member)
return member
def refuse_waiter(member: Member, db: Session):
db.delete(member)
db.commit()
return None
class RoomConsumer(Consumer):
def __init__(self, ws: WebSocket, room: Room, manager: ConnectionManager, db: Session):
def __init__(self, ws: WebSocket, room: Room, manager: ConsumerManager, db: Session):
self.room = room
self.ws = ws
self.manager = manager
self.db = db
self.member = None
#WS Utilities
# WS Utilities
async def connect(self):
await self.ws.accept()
async def send(self, type: str, payload: Any):
async def direct_send(self, type: str, payload: Any):
await self.ws.send_json({'type': type, "data": payload})
async def send_to_all_room(self, type: str, payload: Any, exclude: bool = False):
@ -173,81 +416,170 @@ class RoomConsumer(Consumer):
async def send_to_members(self, type: str, payload: Any, exclude: bool = False):
await self.manager.broadcast({'type': type, "data": payload}, f'{self.room.id}__member', [exclude == True and self.ws])
async def broadcast(self, type, payload, exclude= False):
await self.manager.broadcast({"type": type, "data": payload}, self.room.id, exclude = [exclude == True and self])
def add_to_admin(self):
self.manager.add(f'{self.room.id}__admin', self.ws)
def add_to_members(self):
self.manager.add(f'{self.room.id}__members', self.ws)
def add_to_groups(self):
if isinstance(self.member, Member):
if self.member.is_admin == True:
self.add_to_admin()
if self.member.is_admin == False:
self.add_to_members()
def add_to_group(self):
if self.member.waiting == True:
self.manager.add(f'waiter__{self.member.waiter_code}', self)
self.manager.add(self.room.id, self)
async def connect_self(self):
if isinstance(self.member, Member):
connect_member(self.member, self.db)
await self.send_to_all_room(type="connect", payload={}, exclude=True)
await self.broadcast(type="connect", payload={"member": serialize_member(self.member).dict()})
async def disconnect_self(self):
if isinstance(self.member, Member):
disconnect_member(self.member, self.db)
await self.send_to_all_room(type="disconnect", payload={}, exclude=True)
#DB Utilities
#Events
await self.broadcast(type="disconnect", payload={"member": serialize_member(self.member).dict()})
# DB Utilities
# Received Events
@Consumer.event('login')
async def login(self, data):
if 'token' in data:
token = data.get('token')
user = get_user_from_token(token, db=self.db)
if user == False:
await self.send()
async def login(self, token: str | None = None, reconnect_code: str | None = None):
if token is not None:
member = get_member_from_token(token, self.room.id, self.db)
if member == False:
await self.direct_send(type="error", payload={"msg": "Token expired"})
return
if user is None:
return
member = get_member_from_user(
user_id=user.id, room_id=self.room.id, db=self.db)
if member is None:
await self.direct_send(type="error", payload={"msg": "Utilisateur introuvable dans cette salle"})
return
self.member = member
# await self.connect_self()
self.add_to_group()
await self.direct_send(type="loggedIn", payload={"member": serialize_member(self.member).dict()})
elif reconnect_code is not None:
member = get_member_reconnect_code(
reconnect_code, self.room.id, db=self.db)
if member is None:
await self.direct_send(type="error", payload={"msg": "Utilisateur introuvable dans cette salle"})
return
self.member = member
self.add_to_groups()
self.connect_self()
await self.send()
elif "reconnect_code" in data:
reconnect_code = data.get('reconnect_code')
anonymous = get_anonymous_from_code(
reconnect_code=reconnect_code, db=self.db)
if anonymous is None:
return
member = get_member_from_anonymous(
anonymous_id=anonymous.id, room_id=self.room.id, db=self.db)
if member is None:
return
self.member = member
self.add_to_groups()
self.connect_self()
await self.send(type="accepted")
# await self.connect_self()
self.add_to_group()
await self.direct_send(type="loggedIn", payload={"member": serialize_member(self.member).dict()})
if reconnect_code is None and token is None:
await self.direct_send(type="error", payload={"msg": "Veuillez spécifier une méthode de connection"})
@Consumer.event('join')
async def join(self, data):
if "token" in data:
return
else:
return
return
async def join(self, token: str | None = None, username: str | None = None):
if self.room.public == False:
if token is not None:
user = get_user_from_token(token, self.db)
if user is None:
await self.direct_send(type="error", payload={"msg": "Utilisateur introuvable"})
return
if user is False:
await self.direct_send(type="error", payload={"msg": "Token expired"})
return
waiter = create_user_waiter(user, self.room, self.db)
if waiter.waiting is False:
self.member = waiter
# await self.connect_self()
self.add_to_group()
await self.direct_send(type="loggedIn", payload={"member": serialize_member(self.member).dict()})
return
self.member = waiter
self.add_to_group()
await self.direct_send(type="waiting", payload={"waiter": serialize_member(self.member).dict()})
await self.broadcast(type="waiter", payload={"waiter": serialize_member(self.member).dict()})
elif username is not None:
waiter = create_anonymous_waiter(username, self.room, self.db)
if waiter is None:
await self.direct_send(type="error", payload={"msg": "Nom d'utilisateur invalide ou indisponible"})
return
self.member = waiter
self.add_to_group()
await self.direct_send(type="waiting", payload={"waiter": serialize_member(self.member).dict()})
await self.broadcast(type="waiter", payload={"waiter": serialize_member(self.member).dict()})
else:
if token is not None:
user = get_user_from_token(token, self.db)
if user is None:
return
if user is False:
return
member = create_user_member(user, self.room, self.db)
if member is None:
return
self.member = member
self.add_to_group()
await self.direct_send()
elif username is not None:
member = create_anonymous_member(username, self.room, self.db)
if member is None:
await self.direct_send(type="error", data={"msg": "Nom d'utilisateur indisponible"})
return
self.member = member
self.add_to_group()
await self.direct_send()
def isAdmin(self):
return self.member is not None and self.member.is_admin == True
@Consumer.event('accept', conditions=[isAdmin])
async def accept(self, waiter_id: str):
waiter = get_waiter(waiter_id, self.db)
member = accept_waiter(waiter, self.db)
await self.manager.broadcast({"type": "accepted", "data": {'member': serialize_member(member).dict()}}, f"waiter__{waiter_id}")
await self.broadcast(type="joined", payload={"member": serialize_member(member).dict()})
@Consumer.event('refuse', conditions=[isAdmin])
async def accept(self, waiter_id: str):
waiter = get_waiter(waiter_id, self.db)
member = refuse_waiter(waiter, self.db)
await self.manager.broadcast({"type": "refused", "data": {'waiter_id': waiter_id}}, f"waiter__{waiter_id}")
#await self.broadcast(type="joined", payload={"member": serialize_member(member).dict()})
@Consumer.event('ping_room')
async def proom(self):
await self.broadcast(type='ping', payload={})
def isMember(self):
return self.member is not None and self.member.waiting == False
# Sending Events
@Consumer.sending("joined", conditions=[isMember])
def joined(self, member: MemberRead):
print('MEMBER', self.member, member)
if (self.member.user is not None and member.username == self.member.user.username) or (self.member.anonymous and member.reconnect_code == self.member.anonymous.reconnect_code):
raise ValueError("Nope")
if self.member.is_admin == False:
member.reconnect_code = ""
return {"member": member}
@Consumer.sending('waiter', conditions=[isAdmin])
def waiter(self, waiter: Waiter):
return {"waiter": waiter}
@Consumer.sending('ping', conditions=[isMember])
def ping(self):
return {}
async def disconnect(self):
await self.disconnect_self()
self.manager.remove(self.room.id, self)
#await self.disconnect_self()
@router.websocket('/ws/room/{room_id}')
async def room_ws(ws: WebSocket, room: Room | None = Depends(check_room), db: Session = Depends(get_session)):
if room is None:
@ -255,3 +587,32 @@ async def room_ws(ws: WebSocket, room: Room | None = Depends(check_room), db: Se
status_code=status.HTTP_404_NOT_FOUND, detail='Room not found')
consumer = RoomConsumer(ws=ws, room=room, manager=manager, db=db)
await consumer.run()
class TestConsumer(Consumer):
async def connect(self):
await self.ws.accept()
def test(self):
return True
@Consumer.event("test", conditions=[True, test])
async def testering(self):
await self.ws.send_json({"type": "success"})
await self.send({"type": "test", "data": {"i": {"username": "lilian", "reconnect_code": "something", "isAdmin": False, "isUser": False}, "test": 12}})
# await self.send({"type": "test", "data": {"i": {"username": "lilian", "reconnect_code": "something", "isAdmin": False, "isUser": False}}})
return
@Consumer.sending('test', conditions=[])
def sendtest(self, i: MemberRead, test: int):
print("i", i)
print(i.reconnect_code)
print(dict(i))
i.reconnect_code = "nope"
return {"i": i, "test": test}
@router.websocket('/ws/test')
async def test(ws: WebSocket):
consumer = TestConsumer(ws)
await consumer.run()

View File

@ -0,0 +1,14 @@
from pydantic import *
class Model(BaseModel):
test: str = "test"
i: int
d = {'title': 'Sendtest', 'type': 'object', 'properties': {'i': {
'title': 'I', 'type': 'integer'}}, 'required': ['i'], 'additionalProperties': False}
props = {(k) for k,v in d['properties']}
obj = create_model("model", foo=(str, "str"))
print(Model(i=12, l=12))

View File

@ -3,24 +3,26 @@ from fastapi.testclient import TestClient
from tests.test_auth import test_register
def test_create_room_no_auth(client: TestClient):
def test_create_room_no_auth(client: TestClient, public=False):
r = client.post('/room', json={"name": "test_room",
"public": False}, params={'username': "lilian"})
"public": False}, params={'username': "lilian", "public": public})
print(r.json())
assert "id_code" in r.json()['room']
assert "reconnect_code" in r.json()['member']['anonymous']
assert {"room": {**r.json()['room'], 'id_code': None}, "member": {**r.json()['member'], "anonymous": {**r.json()['member']['anonymous'], "reconnect_code": None}}} == {"room": {"id_code": None, "name": "test_room",
"public": False}, 'member': {"anonymous": {"username": "lilian", "reconnect_code": None}, "user": None}}
assert r.json()['member']['reconnect_code'] is not None
assert {"room": {**r.json()['room'], 'id_code': None}, "member": {**r.json()['member'], "reconnect_code": None}} == {"room": {"id_code": None, "name": "test_room",
"public": False}, 'member': {"username": "lilian", "reconnect_code": None, "isUser": False, "isAdmin": True}}
return r.json()
def test_create_room_no_auth_invalid(client: TestClient):
r = client.post('/room', json={"name": "test_room"*21,
"public": False}, params={'username': "lilian"*21})
print(r.json())
assert r.json() == {'detail': {'username_error': 'ensure this value has at most 20 characters',
'name_error': 'ensure this value has at most 20 characters'}}
def test_create_room_auth(client: TestClient, token = None):
def test_create_room_auth(client: TestClient, token=None):
if token is None:
token = test_register(client=client)['access']
r = client.post('/room', json={"name": "test_room",
@ -28,52 +30,408 @@ def test_create_room_auth(client: TestClient, token = None):
print(r.json())
assert "id_code" in r.json()['room']
assert {**r.json(), "room": {**r.json()['room'], 'id_code': None}} == {"room": {"id_code": None, "name": "test_room",
"public": False}, 'member': {"user": {"username": "lilian"}, "anonymous": None}}
"public": False}, 'member': {"username": "lilian", "reconnect_code": "", "isUser": True, "isAdmin": True}}
return r.json()
def test_room_not_found(client: TestClient):
try:
with client.websocket_connect('/ws/room/eee') as r:
pass
except HTTPException as e :
except HTTPException as e:
assert True
except Exception:
assert False
def test_login_no_auth(client: TestClient):
room = test_create_room_no_auth(client=client)
member = room['member']['anonymous']
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as ws:
ws.send_json({"type": "login", "data": {"reconnect_code": member['reconnect_code']}})
ws.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
data = ws.receive_json()
print(data)
assert data == {'type': "loggedIn", "data": {"member": {"username": member['username'], "reconnect_code": member['reconnect_code'], "isAdmin": True}}}
assert data == {'type': "loggedIn", "data": {"member": {
"username": member['username'], "reconnect_code": member['reconnect_code'], "isAdmin": True, "isUser": False}}}
def test_login_no_auth_not_in_room(client: TestClient):
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as ws:
ws.send_json({"type": "login", "data": {
"reconnect_code": "lol"}})
data = ws.receive_json()
print(data)
assert data == {'type': "error", "data": {
"msg": "Utilisateur introuvable dans cette salle"}}
def test_login_auth(client: TestClient):
token = test_register(client=client)['access']
room = test_create_room_auth(client=client, token=token)
member = room['member']['user']
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as ws:
ws.send_json({"type": "login", "data": {"token": token}})
data = ws.receive_json()
print(data)
assert data == {'type': "loggedIn", "data": {"member": {"username": member['username'], "isAdmin": True}}}
assert data == {'type': "loggedIn", "data": {"member": {
"username": member['username'], "isAdmin": True, "isUser": True, 'reconnect_code': ""}}}
def test_join_no_auth(client: TestClient):
def test_login_auth_not_in_room(client: TestClient):
token = test_register(client=client, username="lilian2")['access']
room = test_create_room_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as ws:
ws.send_json({"type": "login", "data": {"token": token}})
data = ws.receive_json()
print(data)
assert data == {'type': "error", "data": {
"msg": "Utilisateur introuvable dans cette salle"}}
def test_join_auth(client: TestClient):
token = test_register(client, username="lilian2")['access']
room = test_create_room_no_auth(client=client)
member = room['member']['anonymous']
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
admin.receive_json()
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type":"join", "data": {"username": "member"}})
member.send_json({"type": "join", "data": {"token": token}})
mdata = member.receive_json()
assert "waiter_id" in mdata['data']['waiter']
assert mdata == {"type": "waiting", "data": {"waiter": {
"username": "lilian2", "waiter_id": mdata['data']['waiter']['waiter_id']}}}
adata = admin.receive_json()
assert adata == {'type': "waiter", 'data': {
"waiter": {"waiter_id": mdata['data']['waiter']['waiter_id'], "username": "lilian2"}}}
admin.send_json({"type": "accept", "data": {
"waiter_id": mdata['data']['waiter']['waiter_id']}})
mdata = member.receive_json()
assert mdata == {"type": "accepted", "data": {"member": {
"username": "lilian2", "isUser": True, "isAdmin": False, "reconnect_code": ""}}}
adata = admin.receive_json()
assert adata == {'type': "joined", 'data': {
"member": {"reconnect_code": "", "username": "lilian2", "isUser": True, "isAdmin": False}}}
admin.send_json({"type": "ping_room"})
mdata = member.receive_json()
assert mdata == {"type": "ping", "data": {}}
def test_join_no_auth(client: TestClient):
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
admin.receive_json()
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json(
{"type": "join", "data": {"username": "member"}})
mdata = memberws.receive_json()
assert "waiter_id" in mdata['data']['waiter']
assert mdata == {"type": "waiting", "data": {"waiter": {
"username": "member", "waiter_id": mdata['data']['waiter']['waiter_id']}}}
adata = admin.receive_json()
assert adata == {'type': "waiter", 'data': {
"waiter": {"waiter_id": mdata['data']['waiter']['waiter_id'], "username": "member"}}}
admin.send_json({"type": "accept", "data": {
"waiter_id": mdata['data']['waiter']['waiter_id']}})
mdata = memberws.receive_json()
new_reconnect = mdata['data']['member']['reconnect_code']
assert 'reconnect_code' in mdata['data']['member']
assert mdata == {"type": "accepted", "data": {"member": {
"username": "member", "reconnect_code": new_reconnect, "isUser": False, "isAdmin": False}}}
adata = admin.receive_json()
assert adata == {'type': "joined", 'data': {
"member": {"reconnect_code": new_reconnect, "username": "member", "isUser": False, "isAdmin": False}}}
admin.send_json({"type": "ping_room"})
mdata = memberws.receive_json()
assert mdata == {"type": "ping", "data": {}}
return {"room": room, "members": [member['reconnect_code'], new_reconnect]}
def test_join_no_auth_username_error(client: TestClient):
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"username": "lilian"}})
mdata = member.receive_json()
assert mdata == {"type": "error", "data": {
"msg": "Nom d'utilisateur invalide ou indisponible"}}
def test_join_no_auth_username_too_long(client: TestClient):
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"username": "lilian"*21}})
mdata = member.receive_json()
assert mdata == {"type": "error", "data": {"msg": "Nom d'utilisateur invalide ou indisponible"}}
def test_join_auth_refused(client: TestClient):
token = test_register(client, username="lilian2")['access']
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
admin.receive_json()
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"token": token}})
mdata = member.receive_json()
assert "waiter_id" in mdata['data']['waiter']
assert mdata == {"type": "waiting", "data": {"waiter": {
"username": "lilian2", "waiter_id": mdata['data']['waiter']['waiter_id']}}}
waiter_id = mdata['data']['waiter']['waiter_id']
adata = admin.receive_json()
assert adata == {'type': "waiter", 'data': {
"waiter": {"waiter_id": waiter_id, "username": "lilian2"}}}
admin.send_json({"type": "refuse", "data": {
"waiter_id": waiter_id}})
mdata = member.receive_json()
assert mdata == {"type": "refused", "data": {
"waiter_id": waiter_id}}
def test_join_auth_in_room_yet(client: TestClient):
token = test_register(client, username="lilian")['access']
room = test_create_room_auth(client=client, token=token)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"token": token}})
mdata = member.receive_json()
assert mdata == {"type": "loggedIn", "data": {"member": {
"username": "lilian2", "isAdmin": True, "isUser": True}}}
def test_join_auth_public(client: TestClient):
token = test_register(client, username="lilian2")['access']
room = test_create_room_no_auth(client=client, public=True)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"token": token}})
mdata = member.receive_json()
assert mdata == {"type": "accepted", "data": {"member": {
"username": "member", "isUser": True, "isAdmin": False}}}
adata = admin.receive_json()
assert adata == {'type': "joined", 'data': {
"member": {"reconnect_code": "", "username": "member", "isUser": True}}}
admin.send_json({"type": "ping_room"})
mdata = member.receive_json()
assert mdata == {"type": "ping"}
def test_join_no_auth_public(client: TestClient):
room = test_create_room_no_auth(client=client, public=True)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"username": "member"}})
mdata = member.receive_json()
assert 'reconnect_code' in mdata['data']['member']
assert mdata == {"type": "accepted", "data": {"member": {
"username": "member", "reconnect_code": mdata['data']['reconnect_code'], "isUser": False, "isAdmin": False}}}
adata = admin.receive_json()
assert adata == {'type': "joined", 'data': {
"member": {"reconnect_code": mdata['data']['reconnect_code'], "username": "member", "isUser": False}}}
member.send_json({"type": "update_groups"})
admin.send_json({"type": "ping_room"})
mdata = member.receive_json()
assert mdata == {"type": "ping"}
def test_join_no_auth_unauthorized(client: TestClient):
token = test_register(client, username="lilian2")['access']
room = test_create_room_no_auth(client=client)
member = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": member['reconnect_code']}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({"type": "join", "data": {"token": token}})
mdata = member.receive_json()
assert "id_code" in mdata['data']['waiter']
assert mdata == {"type": "waiting", "data": {"waiter": {
"username": "member", "id_code": mdata['data']['waiter']}}}
"username": "lilian2", "id_code": mdata['data']['waiter']}}}
adata = admin.receive_json()
assert adata == {'type': "waiter", 'data': {
"waiter": {"id_code": mdata['data']['waiter'], "username": "member"}}}
admin.send({"type": "accept", "data": {"waiter_id": mdata['data']['waiter']}})
"waiter": {"id_code": mdata['data']['waiter']['id_code'], "username": "member"}}}
member.send_json({"type": "refuse", "data": {
"waiter_id": mdata['data']['waiter']['id_code']}})
mdata = member.receive_json()
assert mdata == {"type": "error", "data": {
"msg": "Vous n'avez pas la permission de faire ca"}}
def test_connect_admin(client: TestClient):
room = test_join_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members[0]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as member:
member.send_json({'type': "login", "data": {
"reconnect_code": members[0]}})
adata = admin.receive_json()
assert adata == {"type": "connect", "data": {"member": {
"username": "member", "reconnect_code": members[1], "isAdmin": False, "isUser": False}}}
def test_connect_member(client: TestClient):
room = test_join_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({'type': "login", "data": {
"reconnect_code": members[0]}})
mdata = memberws.receive_json()
assert mdata == {"type": "connect", "data": {"member": {
"username": "member", "reconnect_code": "", "isAdmin": True, "isUser": False}}}
def test_disconnect(client: TestClient):
room = test_join_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({'type': "login", "data": {
"reconnect_code": members[0]}})
admin.close()
mdata = memberws.receive_json()
assert mdata == {"type": "disconnect", "data": {"member": {
"username": "member", "reconnect_code": "", "isAdmin": True, "isUser": False}}}
def test_leave(client: TestClient):
room = test_join_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
memberws.send_json({"type": "leave"})
data = memberws.receive_json()
assert data == {"type": "successfully_leaved"}
adata = admin.receive_json()
assert adata == {"type": "leaved", "data": {"member": {
"username": "member", "reconnect_code": members[1], "isAdmin": False, "isUser": False}}}
def test_leave_not_connected(client: TestClient):
room = test_create_room_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "leave"})
data = memberws.receive_json()
assert data == {"type": "error", "data": {
"msg": "Vous n'êtes connecté à aucune salle"}}
def test_leave_admin(client: TestClient):
room = test_join_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members[0]}})
admin.send_json({"type": "leave"})
data = admin.receive_json()
assert data == {"type": "error", "data": {
"msg": "Vous ne pouvez pas quitter une salle dont vous êtes l'administrateur"}}
def test_ban_anonymous(client: TestClient):
room = test_create_room_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
admin.send_json({"type": "ban", "data": {"member": {
"username": "member", "reconnect_code": members[1], "isUser": False, "isAdmin": False}}})
adata = admin.receive_json()
assert adata == {"type": "leaved", "data": {"member": {
"username": "member", "reconnect_code": members[1], "isUser": True, "isAdmin": False}}}
def test_ban_anonymous_unauthorized(client: TestClient):
room = test_create_room_no_auth(client=client)
members = room['members']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "login", "data": {
"reconnect_code": members[1]}})
memberws.send_json({"type": "ban", "data": {"member": {
"username": "member", "reconnect_code": members[1], "isUser": False, "isAdmin": False}}})
mdata = memberws.receive_json()
assert mdata == {"type": "error", "data": {
"msg": "Vous n'avez pas les permissions pour faire ça"}}
def test_ban_user(client: TestClient):
token = test_register(client=client, username="lilian2")
room = test_create_room_no_auth(client=client)
members = room['member']
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as admin:
admin.send_json({"type": "login", "data": {
"reconnect_code": members["reconnect_code "]}})
with client.websocket_connect(f"/ws/room/" + room['room']['id_code']) as memberws:
memberws.send_json({"type": "join", "data": {"token": token}})
adata = admin.receive_json()
admin.send_json({"type": "ban", "data": {"member": {
"username": "lilian2", "reconnect_code": "", "isUser": True, "isAdmin": False}}})
adata = admin.receive_json()
assert adata == {"type": "leaved", "data": {"member": {
"username": "lilian2", "reconnect_code": "", "isUser": True, "isAdmin": False}}}