File size: 2,261 Bytes
e586f48
ee0f8bd
 
e586f48
ee0f8bd
e586f48
 
ee0f8bd
e586f48
 
8fb90d0
 
ee0f8bd
 
 
 
e586f48
 
ee0f8bd
 
 
e586f48
 
 
 
 
8fb90d0
e586f48
ee0f8bd
e586f48
ee0f8bd
e586f48
 
 
ee0f8bd
 
 
 
 
7badcff
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
"""Mathly session roles and permissions."""
from __future__ import annotations

from .auth import SupabaseAuth

ROLES = frozenset({"student", "teacher", "admin", "developer"})
DEFAULT_ROLES = ("student",)
ROLE_PERMISSIONS = {
    "student": frozenset({"path.use"}),
    "teacher": frozenset({"path.use", "students.view"}),
    # management (the ניהול sheet: classes, monitoring, every class's data) is for developers only
    "admin": frozenset({"path.use", "students.view"}),
    "developer": frozenset({"*"}),
}


def resolve_access(store: SupabaseAuth, token: str, *, fresh_permissions: bool = False) -> dict | None:
    user = store.user(token)
    if user is None:
        return None
    email = user["email"].lower()
    classes = store.classes()
    mine = [row for row in classes if email in row.get("emails", ()) or email in row.get("teachers", ())]
    assigned = store.access_for(user["id"], fresh=fresh_permissions)
    roles = set((assigned or {}).get("roles") or DEFAULT_ROLES) & ROLES
    if email in store.teachers:
        roles.add("teacher")
    if email in store.developers:
        roles.add("developer")
    if classes and not mine and roles == {"student"}:
        return {**user, "denied": True, "permissions": []}
    permissions = set().union(*(ROLE_PERMISSIONS[role] for role in roles))
    return {**user, "token": token, "roles": sorted(roles), "permissions": sorted(permissions),
            "teacher": bool(roles & {"teacher", "admin", "developer"}), "classes": mine}


def has_permission(user: dict | None, permission: str) -> bool:
    permissions = set((user or {}).get("permissions", ()))
    return "*" in permissions or permission in permissions


def students_of(user: dict, classes) -> set[str] | None:
    """The students (emails) this account reviews: those of the classes it is the teacher of, and None, meaning every
    student, for a manager. Shared by the AI queue and the teacher's review of answers."""
    if has_permission(user, "management.access"):
        return None
    email = str(user.get("email", "")).lower()
    out: set[str] = set()
    for row in classes:
        if email in row.get("teachers", ()):
            out |= set(row.get("emails", ())) - set(row.get("teachers", ()))
    return out