forked from enviPath/enviPy
## Major Changes - Implement a REST style API app in epapi - Currently implements a GET method for all entity types in the browse menu (both package level and global) - Provides paginated results per default with query style filtering for reviewed vs unreviewed. - Provides new paginated templates with thin wrappers per entity types for easier maintainability - Implements e2e tests for the API ## Minor changes - Added more comprehensive gitignore to cover coverage reports and other test/node.js etc. data. - Add additional CI file for API tests that only gets triggered on API relevant changes. ## ⚠️ Currently only works with session-based authentication. Token based will be added in new PR. Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Co-authored-by: jebus <lorsbach@envipath.com> Reviewed-on: enviPath/enviPy#243 Co-authored-by: Tobias O <tobias.olenyi@envipath.com> Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
96 lines
3.3 KiB
Python
96 lines
3.3 KiB
Python
from django.db.models import Model
|
|
from epdb.logic import PackageManager
|
|
from epdb.models import CompoundStructure, User, Package, Compound
|
|
from uuid import UUID
|
|
|
|
from .errors import EPAPINotFoundError, EPAPIPermissionDeniedError
|
|
|
|
|
|
def get_compound_or_error(user, compound_uuid: UUID):
|
|
"""
|
|
Get compound by UUID with permission check.
|
|
"""
|
|
try:
|
|
compound = Compound.objects.get(uuid=compound_uuid)
|
|
package = compound.package
|
|
except Compound.DoesNotExist:
|
|
raise EPAPINotFoundError(f"Compound with UUID {compound_uuid} not found")
|
|
|
|
# FIXME: optimize package manager to exclusively work with UUIDs
|
|
if not user or user.is_anonymous or not PackageManager.readable(user, package):
|
|
raise EPAPIPermissionDeniedError("Insufficient permissions to access this compound.")
|
|
|
|
return compound
|
|
|
|
|
|
def get_package_or_error(user, package_uuid: UUID):
|
|
"""
|
|
Get package by UUID with permission check.
|
|
"""
|
|
|
|
# FIXME: update package manager with custom exceptions to avoid manual checks here
|
|
try:
|
|
package = Package.objects.get(uuid=package_uuid)
|
|
except Package.DoesNotExist:
|
|
raise EPAPINotFoundError(f"Package with UUID {package_uuid} not found")
|
|
|
|
# FIXME: optimize package manager to exclusively work with UUIDs
|
|
if not user or user.is_anonymous or not PackageManager.readable(user, package):
|
|
raise EPAPIPermissionDeniedError("Insufficient permissions to access this package.")
|
|
|
|
return package
|
|
|
|
|
|
def get_user_packages_qs(user: User | None):
|
|
"""Get all packages readable by the user."""
|
|
if not user or user.is_anonymous:
|
|
return PackageManager.get_reviewed_packages()
|
|
return PackageManager.get_all_readable_packages(user, include_reviewed=True)
|
|
|
|
|
|
def get_user_entities_qs(model_class: Model, user: User | None):
|
|
"""Build queryset for reviewed package entities."""
|
|
|
|
if not user or user.is_anonymous:
|
|
return model_class.objects.filter(package__reviewed=True).select_related("package")
|
|
|
|
qs = model_class.objects.filter(
|
|
package__in=PackageManager.get_all_readable_packages(user, include_reviewed=True)
|
|
).select_related("package")
|
|
return qs
|
|
|
|
|
|
def get_package_scoped_entities_qs(
|
|
model_class: Model, package_uuid: UUID, user: User | None = None
|
|
):
|
|
"""Build queryset for specific package entities."""
|
|
package = get_package_or_error(user, package_uuid)
|
|
qs = model_class.objects.filter(package=package).select_related("package")
|
|
return qs
|
|
|
|
|
|
def get_user_structures_qs(user: User | None):
|
|
"""Build queryset for structures accessible to the user (via compound->package)."""
|
|
|
|
if not user or user.is_anonymous:
|
|
return CompoundStructure.objects.filter(compound__package__reviewed=True).select_related(
|
|
"compound__package"
|
|
)
|
|
|
|
qs = CompoundStructure.objects.filter(
|
|
compound__package__in=PackageManager.get_all_readable_packages(user, include_reviewed=True)
|
|
).select_related("compound__package")
|
|
return qs
|
|
|
|
|
|
def get_package_compound_scoped_structure_qs(
|
|
package_uuid: UUID, compound_uuid: UUID, user: User | None = None
|
|
):
|
|
"""Build queryset for specific package compound structures."""
|
|
|
|
get_package_or_error(user, package_uuid)
|
|
compound = get_compound_or_error(user, compound_uuid)
|
|
|
|
qs = CompoundStructure.objects.filter(compound=compound).select_related("compound__package")
|
|
return qs
|