| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- """Which owned rows (archives, queue jobs, library files) a caller reaches through something that holds them."""
- from backend.app.core.auth import ApiKeyActor
- from backend.app.core.permissions import Permission
- from backend.app.core.printer_scope import PrinterScope
- from backend.app.models.archive import PrintArchive
- from backend.app.models.print_queue import PrintQueueItem
- from backend.app.models.user import User
- def owned_row_clauses(
- model, actor: User | ApiKeyActor | None, all_permission: Permission, own_permission: Permission
- ) -> list | None:
- """WHERE clauses for the rows of ``model`` the caller may reach by ownership, or None for none.
- Their own unless they may reach everyone's (a row without an owner then
- stays out). Auth off (no actor) reaches all.
- """
- if actor is None:
- return []
- # A key acts with its owner's rights to these rows, not with its own scope
- # flags (a project key needs no archive or queue flag, #1893), so it never
- # reaches a row its owner could not. A legacy key without an owner keeps
- # every row.
- user = actor.owner if isinstance(actor, ApiKeyActor) else actor
- if user is None or user.has_permission(all_permission.value):
- return []
- if user.has_permission(own_permission.value):
- return [model.created_by_id == user.id]
- return None
- def visible_row_clauses(
- model: type[PrintArchive] | type[PrintQueueItem],
- printer_scope: PrinterScope,
- actor: User | ApiKeyActor | None,
- all_permission: Permission,
- own_permission: Permission,
- *,
- by_runs: bool = False,
- ) -> list | None:
- """WHERE clauses for the archive or queue rows the caller may reach, or None for none.
- The rows the caller reaches through the archives or the queue themselves:
- on their printers, and by ``owned_row_clauses``. ``by_runs``: archives
- printed on one of their printers too (``archive_scope_clause``), for a
- listing that shows them as the caller sees them (the archives routes'
- ``_scoped``); others show an archive's latest print as it is.
- """
- owned = owned_row_clauses(model, actor, all_permission, own_permission)
- if owned is None:
- return None
- clause = (
- archive_scope_clause(printer_scope)
- if model is PrintArchive and by_runs
- else printer_scope.where(model.printer_id)
- )
- if clause is not None:
- return [clause, *owned]
- return owned
- def archive_scope_clause(printer_scope: PrinterScope):
- """The archives a printer scope sees (#1727), as a WHERE clause; None
- when it sees every printer. An archive is a file printed as runs, maybe
- on several printers (archive redesign): it is seen on its own printer
- (the latest run's, or none) and on every printer one of its runs printed
- on, a print running now included.
- """
- from sqlalchemy import or_, select
- from backend.app.models.print_log import PrintLogEntry
- own = printer_scope.where(PrintArchive.printer_id)
- if own is None:
- return None
- # The table, not the entity: the ORM hides open runs from every read of
- # PrintLogEntry, and a print running on the caller's printer counts.
- runs = PrintLogEntry.__table__
- printed_here = select(runs.c.archive_id).where(
- runs.c.archive_id.is_not(None), runs.c.printer_id.in_(printer_scope.printer_ids or ())
- )
- return or_(own, PrintArchive.id.in_(printed_here))
- def whole_archive_scope_clause(printer_scope: PrinterScope):
- """The archives every print of which the scope sees, as a WHERE clause;
- None when it sees every printer. What changes or removes the whole
- archive (its file, its video, the archive itself) needs this: it would
- change other printers' prints too (archive redesign)."""
- from sqlalchemy import and_, not_, select
- from backend.app.models.print_log import PrintLogEntry
- own = printer_scope.where(PrintArchive.printer_id)
- if own is None:
- return None
- runs = PrintLogEntry.__table__
- printed_elsewhere = select(runs.c.archive_id).where(
- runs.c.archive_id.is_not(None),
- runs.c.printer_id.is_not(None),
- runs.c.printer_id.not_in(printer_scope.printer_ids or ()),
- )
- return and_(own, not_(PrintArchive.id.in_(printed_elsewhere)))
- def may_reach_row(
- created_by_id: int | None,
- actor: User | ApiKeyActor | None,
- all_permission: Permission,
- own_permission: Permission,
- ) -> bool:
- """Whether the caller may reach one row owned by ``created_by_id``, printer scope aside.
- The rule of ``visible_row_clauses`` for a row already loaded.
- """
- if actor is None:
- return True
- user = actor.owner if isinstance(actor, ApiKeyActor) else actor
- if user is None or user.has_permission(all_permission.value):
- return True
- return user.has_permission(own_permission.value) and created_by_id is not None and created_by_id == user.id
|