mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-30 18:13:23 +08:00
Refactor quotas API
- Use DecodedDatabaseIdField - Build response models with `construct` to avoid validation before serialization
This commit is contained in:
@@ -23,7 +23,6 @@ from galaxy.quota._schema import (
|
||||
DefaultQuotaValues,
|
||||
QuotaOperation,
|
||||
)
|
||||
from galaxy.schema.fields import EncodedDatabaseIdField
|
||||
from galaxy.structured_app import StructuredApp
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -257,5 +256,5 @@ class QuotaManager:
|
||||
message += ", ".join(names)
|
||||
return message
|
||||
|
||||
def get_quota(self, trans, id: EncodedDatabaseIdField, deleted: Optional[bool] = None) -> model.Quota:
|
||||
def get_quota(self, trans, id: int, deleted: Optional[bool] = None) -> model.Quota:
|
||||
return base.get_object(trans, id, "Quota", check_ownership=False, check_accessible=False, deleted=deleted)
|
||||
|
||||
+12
-14
@@ -4,17 +4,15 @@ from typing import (
|
||||
Optional,
|
||||
)
|
||||
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
Field,
|
||||
)
|
||||
from pydantic import Field
|
||||
|
||||
from galaxy.schema.fields import (
|
||||
EncodedDatabaseIdField,
|
||||
DecodedDatabaseIdField,
|
||||
ModelClassField,
|
||||
)
|
||||
from galaxy.schema.schema import (
|
||||
GroupModel,
|
||||
Model,
|
||||
UserModel,
|
||||
)
|
||||
|
||||
@@ -67,7 +65,7 @@ QuotaOperationField = Field(
|
||||
)
|
||||
|
||||
|
||||
class DefaultQuota(BaseModel): # TODO: should this replace lib.galaxy.model.DefaultQuotaAssociation at some point?
|
||||
class DefaultQuota(Model): # TODO: should this replace lib.galaxy.model.DefaultQuotaAssociation at some point?
|
||||
model_class: str = ModelClassField(DEFAULT_QUOTA_ASSOCIATION_MODEL_CLASS_NAME)
|
||||
type: DefaultQuotaTypes = Field(
|
||||
...,
|
||||
@@ -80,7 +78,7 @@ class DefaultQuota(BaseModel): # TODO: should this replace lib.galaxy.model.Def
|
||||
)
|
||||
|
||||
|
||||
class UserQuota(BaseModel):
|
||||
class UserQuota(Model):
|
||||
model_class: str = ModelClassField(USER_QUOTA_ASSOCIATION_MODEL_CLASS_NAME)
|
||||
user: UserModel = Field(
|
||||
...,
|
||||
@@ -89,7 +87,7 @@ class UserQuota(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class GroupQuota(BaseModel):
|
||||
class GroupQuota(Model):
|
||||
model_class: str = ModelClassField(GROUP_QUOTA_ASSOCIATION_MODEL_CLASS_NAME)
|
||||
group: GroupModel = Field(
|
||||
...,
|
||||
@@ -98,11 +96,11 @@ class GroupQuota(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class QuotaBase(BaseModel):
|
||||
class QuotaBase(Model):
|
||||
"""Base model containing common fields for Quotas."""
|
||||
|
||||
model_class: str = ModelClassField(QUOTA_MODEL_CLASS_NAME)
|
||||
id: EncodedDatabaseIdField = Field(
|
||||
id: DecodedDatabaseIdField = Field(
|
||||
...,
|
||||
title="ID",
|
||||
description="The `encoded identifier` of the quota.",
|
||||
@@ -121,7 +119,7 @@ class QuotaSummary(QuotaBase):
|
||||
)
|
||||
|
||||
|
||||
class QuotaSummaryList(BaseModel):
|
||||
class QuotaSummaryList(Model):
|
||||
__root__: List[QuotaSummary] = Field(
|
||||
default=[],
|
||||
title="List with summary information of Quotas.",
|
||||
@@ -166,7 +164,7 @@ class CreateQuotaResult(QuotaSummary):
|
||||
)
|
||||
|
||||
|
||||
class CreateQuotaParams(BaseModel):
|
||||
class CreateQuotaParams(Model):
|
||||
name: str = QuotaNameField
|
||||
description: str = QuotaDescriptionField
|
||||
amount: str = Field(
|
||||
@@ -196,7 +194,7 @@ class CreateQuotaParams(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class UpdateQuotaParams(BaseModel):
|
||||
class UpdateQuotaParams(Model):
|
||||
name: Optional[str] = Field(
|
||||
default=None,
|
||||
title="Name",
|
||||
@@ -243,7 +241,7 @@ class UpdateQuotaParams(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class DeleteQuotaPayload(BaseModel):
|
||||
class DeleteQuotaPayload(Model):
|
||||
purge: bool = Field(
|
||||
False,
|
||||
title="Purge",
|
||||
|
||||
@@ -196,7 +196,7 @@ class Model(BaseModel):
|
||||
class UserModel(Model):
|
||||
"""User in a transaction context."""
|
||||
|
||||
id: EncodedDatabaseIdField = Field(title="ID", description="User ID")
|
||||
id: DecodedDatabaseIdField = Field(title="ID", description="User ID")
|
||||
username: str = Field(title="Username", description="User username")
|
||||
email: str = Field(title="Email", description="User email")
|
||||
active: bool = Field(title="Active", description="User is active")
|
||||
@@ -205,11 +205,11 @@ class UserModel(Model):
|
||||
model_class: str = ModelClassField(USER_MODEL_CLASS_NAME)
|
||||
|
||||
|
||||
class GroupModel(BaseModel):
|
||||
class GroupModel(Model):
|
||||
"""User group model"""
|
||||
|
||||
model_class: str = ModelClassField(GROUP_MODEL_CLASS_NAME)
|
||||
id: EncodedDatabaseIdField = Field(
|
||||
id: DecodedDatabaseIdField = Field(
|
||||
..., # Required
|
||||
title="ID",
|
||||
description="Encoded group ID",
|
||||
|
||||
@@ -15,13 +15,13 @@ from galaxy.quota._schema import (
|
||||
QuotaSummaryList,
|
||||
UpdateQuotaParams,
|
||||
)
|
||||
from galaxy.schema.fields import EncodedDatabaseIdField
|
||||
from galaxy.webapps.galaxy.services.quotas import QuotasService
|
||||
from . import (
|
||||
from galaxy.schema.fields import DecodedDatabaseIdField
|
||||
from galaxy.webapps.galaxy.api import (
|
||||
depends,
|
||||
DependsOnTrans,
|
||||
Router,
|
||||
)
|
||||
from galaxy.webapps.galaxy.services.quotas import QuotasService
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -29,7 +29,7 @@ log = logging.getLogger(__name__)
|
||||
router = Router(tags=["quotas"])
|
||||
|
||||
|
||||
QuotaIdPathParam: EncodedDatabaseIdField = Path(
|
||||
QuotaIdPathParam: DecodedDatabaseIdField = Path(
|
||||
..., title="Quota ID", description="The encoded identifier of the Quota." # Required
|
||||
)
|
||||
|
||||
@@ -64,24 +64,26 @@ class FastAPIQuota:
|
||||
|
||||
@router.get(
|
||||
"/api/quotas/{id}",
|
||||
name="quota",
|
||||
summary="Displays details on a particular active quota.",
|
||||
require_admin=True,
|
||||
)
|
||||
def show(
|
||||
self, trans: ProvidesUserContext = DependsOnTrans, id: EncodedDatabaseIdField = QuotaIdPathParam
|
||||
self, trans: ProvidesUserContext = DependsOnTrans, id: DecodedDatabaseIdField = QuotaIdPathParam
|
||||
) -> QuotaDetails:
|
||||
"""Displays details on a particular active quota."""
|
||||
return self.service.show(trans, id)
|
||||
|
||||
@router.get(
|
||||
"/api/quotas/deleted/{id}",
|
||||
name="deleted_quota",
|
||||
summary="Displays details on a particular quota that has been deleted.",
|
||||
require_admin=True,
|
||||
)
|
||||
def show_deleted(
|
||||
self,
|
||||
trans: ProvidesUserContext = DependsOnTrans,
|
||||
id: EncodedDatabaseIdField = QuotaIdPathParam,
|
||||
id: DecodedDatabaseIdField = QuotaIdPathParam,
|
||||
) -> QuotaDetails:
|
||||
"""Displays details on a particular quota that has been deleted."""
|
||||
return self.service.show(trans, id, deleted=True)
|
||||
@@ -107,7 +109,7 @@ class FastAPIQuota:
|
||||
def update(
|
||||
self,
|
||||
payload: UpdateQuotaParams,
|
||||
id: EncodedDatabaseIdField = QuotaIdPathParam,
|
||||
id: DecodedDatabaseIdField = QuotaIdPathParam,
|
||||
trans: ProvidesUserContext = DependsOnTrans,
|
||||
) -> str:
|
||||
"""Updates an existing quota."""
|
||||
@@ -120,7 +122,7 @@ class FastAPIQuota:
|
||||
)
|
||||
def delete(
|
||||
self,
|
||||
id: EncodedDatabaseIdField = QuotaIdPathParam,
|
||||
id: DecodedDatabaseIdField = QuotaIdPathParam,
|
||||
trans: ProvidesUserContext = DependsOnTrans,
|
||||
payload: DeleteQuotaPayload = Body(None), # Optional
|
||||
) -> str:
|
||||
@@ -134,7 +136,7 @@ class FastAPIQuota:
|
||||
)
|
||||
def undelete(
|
||||
self,
|
||||
id: EncodedDatabaseIdField = QuotaIdPathParam,
|
||||
id: DecodedDatabaseIdField = QuotaIdPathParam,
|
||||
trans: ProvidesUserContext = DependsOnTrans,
|
||||
) -> str:
|
||||
"""Restores a previously deleted quota."""
|
||||
|
||||
@@ -21,7 +21,7 @@ from galaxy.quota._schema import (
|
||||
QuotaSummaryList,
|
||||
UpdateQuotaParams,
|
||||
)
|
||||
from galaxy.schema.fields import EncodedDatabaseIdField
|
||||
from galaxy.schema.fields import DecodedDatabaseIdField
|
||||
from galaxy.security.idencoding import IdEncodingHelper
|
||||
from galaxy.web import url_for
|
||||
from galaxy.webapps.galaxy.services.base import ServiceBase
|
||||
@@ -37,7 +37,7 @@ class QuotasService(ServiceBase):
|
||||
self.quota_manager = quota_manager
|
||||
|
||||
def index(self, trans: ProvidesUserContext, deleted: bool = False) -> QuotaSummaryList:
|
||||
"""Displays a collection (list) of quotas."""
|
||||
"""Displays a list of quotas."""
|
||||
rval = []
|
||||
query = trans.sa_session.query(model.Quota)
|
||||
if deleted:
|
||||
@@ -47,29 +47,31 @@ class QuotasService(ServiceBase):
|
||||
route = "quota"
|
||||
query = query.filter(model.Quota.deleted == false())
|
||||
for quota in query:
|
||||
item = quota.to_dict(value_mapper={"id": trans.security.encode_id})
|
||||
encoded_id = trans.security.encode_id(quota.id)
|
||||
item["url"] = self._url_for(route, id=encoded_id)
|
||||
item = quota.to_dict(value_mapper={"id": DecodedDatabaseIdField.encode})
|
||||
encoded_id = DecodedDatabaseIdField.encode(quota.id)
|
||||
item["url"] = url_for(route, id=encoded_id)
|
||||
rval.append(item)
|
||||
return QuotaSummaryList.parse_obj(rval)
|
||||
return QuotaSummaryList.construct(__root__=rval)
|
||||
|
||||
def show(self, trans: ProvidesUserContext, id: EncodedDatabaseIdField, deleted: bool = False) -> QuotaDetails:
|
||||
def show(self, trans: ProvidesUserContext, id: DecodedDatabaseIdField, deleted: bool = False) -> QuotaDetails:
|
||||
"""Displays information about a quota."""
|
||||
quota = self.quota_manager.get_quota(trans, id, deleted=deleted)
|
||||
rval = quota.to_dict(view="element", value_mapper={"id": trans.security.encode_id, "total_disk_usage": float})
|
||||
return QuotaDetails.parse_obj(rval)
|
||||
rval = quota.to_dict(
|
||||
view="element", value_mapper={"id": DecodedDatabaseIdField.encode, "total_disk_usage": float}
|
||||
)
|
||||
return QuotaDetails.construct(**rval)
|
||||
|
||||
def create(self, trans: ProvidesUserContext, params: CreateQuotaParams) -> CreateQuotaResult:
|
||||
"""Creates a new quota."""
|
||||
payload = params.dict()
|
||||
self.validate_in_users_and_groups(trans, payload)
|
||||
quota, message = self.quota_manager.create_quota(payload)
|
||||
item = quota.to_dict(value_mapper={"id": trans.security.encode_id})
|
||||
item["url"] = self._url_for("quota", id=trans.security.encode_id(quota.id))
|
||||
item = quota.to_dict(value_mapper={"id": DecodedDatabaseIdField.encode})
|
||||
item["url"] = url_for("quota", id=DecodedDatabaseIdField.encode(quota.id))
|
||||
item["message"] = message
|
||||
return CreateQuotaResult.parse_obj(item)
|
||||
return CreateQuotaResult.construct(**item)
|
||||
|
||||
def update(self, trans: ProvidesUserContext, id: EncodedDatabaseIdField, params: UpdateQuotaParams) -> str:
|
||||
def update(self, trans: ProvidesUserContext, id: DecodedDatabaseIdField, params: UpdateQuotaParams) -> str:
|
||||
"""Modifies a quota."""
|
||||
payload = params.dict()
|
||||
self.validate_in_users_and_groups(trans, payload)
|
||||
@@ -96,7 +98,7 @@ class QuotasService(ServiceBase):
|
||||
return "; ".join(messages)
|
||||
|
||||
def delete(
|
||||
self, trans: ProvidesUserContext, id: EncodedDatabaseIdField, payload: Optional[DeleteQuotaPayload] = None
|
||||
self, trans: ProvidesUserContext, id: DecodedDatabaseIdField, payload: Optional[DeleteQuotaPayload] = None
|
||||
) -> str:
|
||||
"""Marks a quota as deleted."""
|
||||
quota = self.quota_manager.get_quota(
|
||||
@@ -107,7 +109,7 @@ class QuotasService(ServiceBase):
|
||||
message += self.quota_manager.purge_quota(quota)
|
||||
return message
|
||||
|
||||
def undelete(self, trans: ProvidesUserContext, id: EncodedDatabaseIdField) -> str:
|
||||
def undelete(self, trans: ProvidesUserContext, id: DecodedDatabaseIdField) -> str:
|
||||
"""Restores a previously deleted quota."""
|
||||
quota = self.quota_manager.get_quota(trans, id, deleted=True)
|
||||
return self.quota_manager.undelete_quota(quota)
|
||||
@@ -146,9 +148,3 @@ class QuotasService(ServiceBase):
|
||||
raise Exception(msg)
|
||||
payload["in_users"] = list(map(str, new_in_users))
|
||||
payload["in_groups"] = list(map(str, new_in_groups))
|
||||
|
||||
def _url_for(self, *args, **kargs):
|
||||
try:
|
||||
return url_for(*args, **kargs)
|
||||
except AttributeError:
|
||||
return "*deprecated attribute not filled in by FastAPI server*"
|
||||
|
||||
Reference in New Issue
Block a user