Skip to content

Commit

Permalink
Merge branch 'release_24.1' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdbeek committed Aug 13, 2024
2 parents ac0bf8d + 0bc1a46 commit 6e98bc8
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 41 deletions.
10 changes: 8 additions & 2 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12918,7 +12918,10 @@ export interface components {
* @enum {string}
*/
type: "aws_s3" | "azure_blob" | "boto3" | "disk" | "generic_s3";
/** Uuid */
/**
* Uuid
* Format: uuid4
*/
uuid: string;
/** Variables */
variables: {
Expand Down Expand Up @@ -12992,7 +12995,10 @@ export interface components {
type: "ftp" | "posix" | "s3fs" | "azure";
/** Uri Root */
uri_root: string;
/** Uuid */
/**
* Uuid
* Format: uuid4
*/
uuid: string;
/** Variables */
variables: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ const canDelete = computed(() => {
const datasetManipulation = computed(() => {
return !!(containsFileOrFolder.value && Galaxy.user);
});
const totalRows = computed(() => {
return props.metadata?.total_rows ?? 0;
});
function updateSearch(value: string) {
emit("updateSearch", value);
Expand All @@ -106,7 +109,8 @@ async function getSelected() {
const selected = await services.getFilteredFolderContents(
props.folderId,
props.unselected,
props.searchText
props.searchText,
totalRows.value
);
emit("setBusy", false);
Expand Down
7 changes: 4 additions & 3 deletions client/src/components/Libraries/LibraryFolder/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ export class Services {
}
}

async getFilteredFolderContents(id, excluded, searchText) {
async getFilteredFolderContents(id, excluded, searchText, limit) {
// The intent of this method is to get folder contents applying
// seachText filters only; we explicitly set limit to 0
// seachText filters only; limit should match the total number of
// items in the folder, so that all items are returned.
const config = {
params: {
limit: 0,
limit,
},
};
searchText = searchText?.trim();
Expand Down
5 changes: 5 additions & 0 deletions lib/galaxy/exceptions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ class UserCannotRunAsException(MessageException):
err_code = error_codes_by_name["USER_CANNOT_RUN_AS"]


class UserRequiredException(MessageException):
status_code = 403
err_code = error_codes_by_name["USER_REQUIRED"]


class AdminRequiredException(MessageException):
status_code = 403
err_code = error_codes_by_name["ADMIN_REQUIRED"]
Expand Down
5 changes: 5 additions & 0 deletions lib/galaxy/exceptions/error_codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@
"code": 403007,
"message": "Action requires account activation."
},
{
"name": "USER_REQUIRED",
"code": 403008,
"message": "Action requires user authentication."
},
{
"name": "USER_OBJECT_NOT_FOUND",
"code": 404001,
Expand Down
10 changes: 5 additions & 5 deletions lib/galaxy/jobs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2005,13 +2005,13 @@ def fail(message=job.info, exception=None):
# Once datasets are collected, set the total dataset size (includes extra files)
for dataset_assoc in job.output_datasets:
dataset = dataset_assoc.dataset.dataset
if not dataset.purged:
# assume all datasets in a job get written to the same objectstore
quota_source_info = dataset.quota_source_info
collected_bytes += dataset.set_total_size()
else:
# assume all datasets in a job get written to the same objectstore
quota_source_info = dataset.quota_source_info
collected_bytes += dataset.set_total_size()
if dataset.purged:
# Purge, in case job wrote directly to object store
dataset.full_delete()
collected_bytes = 0

user = job.user
if user and collected_bytes > 0 and quota_source_info is not None and quota_source_info.use:
Expand Down
19 changes: 10 additions & 9 deletions lib/galaxy/managers/file_source_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from pydantic import (
BaseModel,
UUID4,
ValidationError,
)

Expand Down Expand Up @@ -87,7 +88,7 @@


class UserFileSourceModel(BaseModel):
uuid: str
uuid: UUID4
uri_root: str
name: str
description: Optional[str]
Expand Down Expand Up @@ -142,16 +143,16 @@ def index(self, trans: ProvidesUserContext) -> List[UserFileSourceModel]:
stores = self._sa_session.query(UserFileSource).filter(UserFileSource.user_id == trans.user.id).all()
return [self._to_model(trans, s) for s in stores]

def show(self, trans: ProvidesUserContext, uuid: str) -> UserFileSourceModel:
def show(self, trans: ProvidesUserContext, uuid: UUID4) -> UserFileSourceModel:
user_file_source = self._get(trans, uuid)
return self._to_model(trans, user_file_source)

def purge_instance(self, trans: ProvidesUserContext, uuid: str) -> None:
def purge_instance(self, trans: ProvidesUserContext, uuid: UUID4) -> None:
persisted_file_source = self._get(trans, uuid)
purge_template_instance(trans, persisted_file_source, self._app_config)

def modify_instance(
self, trans: ProvidesUserContext, id: str, payload: ModifyInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: ModifyInstancePayload
) -> UserFileSourceModel:
if isinstance(payload, UpgradeInstancePayload):
return self._upgrade_instance(trans, id, payload)
Expand All @@ -162,7 +163,7 @@ def modify_instance(
return self._update_instance(trans, id, payload)

def _upgrade_instance(
self, trans: ProvidesUserContext, id: str, payload: UpgradeInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpgradeInstancePayload
) -> UserFileSourceModel:
persisted_file_source = self._get(trans, id)
template = self._get_template(persisted_file_source, payload.template_version)
Expand All @@ -181,15 +182,15 @@ def _upgrade_instance(
return self._to_model(trans, persisted_file_source)

def _update_instance(
self, trans: ProvidesUserContext, id: str, payload: UpdateInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpdateInstancePayload
) -> UserFileSourceModel:
persisted_file_source = self._get(trans, id)
template = self._get_template(persisted_file_source)
update_template_instance(self._sa_session, persisted_file_source, payload, template)
return self._to_model(trans, persisted_file_source)

def _update_instance_secret(
self, trans: ProvidesUserContext, id: str, payload: UpdateInstanceSecretPayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpdateInstanceSecretPayload
) -> UserFileSourceModel:
persisted_file_source = self._get(trans, id)
template = self._get_template(persisted_file_source)
Expand Down Expand Up @@ -300,10 +301,10 @@ def _connection_status(
exception = e
return file_source, connection_exception_to_status("file source", exception)

def _index_filter(self, uuid: str):
def _index_filter(self, uuid: UUID4):
return UserFileSource.__table__.c.uuid == uuid

def _get(self, trans: ProvidesUserContext, uuid: str) -> UserFileSource:
def _get(self, trans: ProvidesUserContext, uuid: UUID4) -> UserFileSource:
filter = self._index_filter(uuid)
user_file_source = self._sa_session.query(UserFileSource).filter(filter).one_or_none()
if user_file_source is None:
Expand Down
20 changes: 11 additions & 9 deletions lib/galaxy/managers/object_store_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
)
from uuid import uuid4

from pydantic import UUID4

from galaxy.exceptions import (
ItemOwnershipException,
RequestParameterInvalidException,
Expand Down Expand Up @@ -73,7 +75,7 @@


class UserConcreteObjectStoreModel(ConcreteObjectStoreModel):
uuid: str
uuid: UUID4
type: ObjectStoreTemplateType
template_id: str
template_version: int
Expand Down Expand Up @@ -106,7 +108,7 @@ def summaries(self) -> ObjectStoreTemplateSummaries:
return self._catalog.summaries

def modify_instance(
self, trans: ProvidesUserContext, id: str, payload: ModifyInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: ModifyInstancePayload
) -> UserConcreteObjectStoreModel:
if isinstance(payload, UpgradeInstancePayload):
return self._upgrade_instance(trans, id, payload)
Expand All @@ -116,12 +118,12 @@ def modify_instance(
assert isinstance(payload, UpdateInstancePayload)
return self._update_instance(trans, id, payload)

def purge_instance(self, trans: ProvidesUserContext, id: str) -> None:
def purge_instance(self, trans: ProvidesUserContext, id: UUID4) -> None:
persisted_object_store = self._get(trans, id)
purge_template_instance(trans, persisted_object_store, self._app_config)

def _upgrade_instance(
self, trans: ProvidesUserContext, id: str, payload: UpgradeInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpgradeInstancePayload
) -> UserConcreteObjectStoreModel:
persisted_object_store = self._get(trans, id)
template = self._get_template(persisted_object_store, payload.template_version)
Expand All @@ -140,15 +142,15 @@ def _upgrade_instance(
return self._to_model(trans, persisted_object_store)

def _update_instance(
self, trans: ProvidesUserContext, id: str, payload: UpdateInstancePayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpdateInstancePayload
) -> UserConcreteObjectStoreModel:
persisted_object_store = self._get(trans, id)
template = self._get_template(persisted_object_store)
update_template_instance(self._sa_session, persisted_object_store, payload, template)
return self._to_model(trans, persisted_object_store)

def _update_instance_secret(
self, trans: ProvidesUserContext, id: str, payload: UpdateInstanceSecretPayload
self, trans: ProvidesUserContext, id: UUID4, payload: UpdateInstanceSecretPayload
) -> UserConcreteObjectStoreModel:
persisted_object_store = self._get(trans, id)
template = self._get_template(persisted_object_store)
Expand Down Expand Up @@ -200,14 +202,14 @@ def index(self, trans: ProvidesUserContext) -> List[UserConcreteObjectStoreModel
stores = self._sa_session.query(UserObjectStore).filter(UserObjectStore.user_id == trans.user.id).all()
return [self._to_model(trans, s) for s in stores]

def show(self, trans: ProvidesUserContext, id: str) -> UserConcreteObjectStoreModel:
def show(self, trans: ProvidesUserContext, id: UUID4) -> UserConcreteObjectStoreModel:
user_object_store = self._get(trans, id)
return self._to_model(trans, user_object_store)

def _save(self, persisted_object_store: UserObjectStore) -> None:
save_template_instance(self._sa_session, persisted_object_store)

def _get(self, trans: ProvidesUserContext, id: str) -> UserObjectStore:
def _get(self, trans: ProvidesUserContext, id: UUID4) -> UserObjectStore:
filter = self._index_filter(id)
user_object_store = self._sa_session.query(UserObjectStore).filter(filter).one_or_none()
if user_object_store is None:
Expand Down Expand Up @@ -274,7 +276,7 @@ def _connection_status(
exception = e
return object_store, connection_exception_to_status("storage location", exception)

def _index_filter(self, uuid: str):
def _index_filter(self, uuid: UUID4):
return UserObjectStore.__table__.c.uuid == uuid

def _get_template(
Expand Down
6 changes: 3 additions & 3 deletions lib/galaxy/model/store/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,9 @@ def handle_dataset_object_edit(dataset_instance, dataset_attrs):
assert file_source_root
dataset_extra_files_path = os.path.join(file_source_root, dataset_extra_files_path)
persist_extra_files(self.object_store, dataset_extra_files_path, dataset_instance)
# Don't trust serialized file size
dataset_instance.dataset.file_size = None
dataset_instance.dataset.set_total_size() # update the filesize record in the database
# Only trust file size if the dataset is purged. If we keep the data we should check the file size.
dataset_instance.dataset.file_size = None
dataset_instance.dataset.set_total_size() # update the filesize record in the database

if dataset_instance.deleted:
dataset_instance.dataset.deleted = True
Expand Down
15 changes: 14 additions & 1 deletion lib/galaxy/webapps/galaxy/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
from galaxy.exceptions import (
AdminRequiredException,
UserCannotRunAsException,
UserRequiredException,
)
from galaxy.managers.session import GalaxySessionManager
from galaxy.managers.users import UserManager
Expand Down Expand Up @@ -183,6 +184,17 @@ def get_user(
return api_user


def get_required_user(
galaxy_session=cast(Optional[model.GalaxySession], Depends(get_session)),
api_user=cast(Optional[User], Depends(get_api_user)),
) -> User:
if galaxy_session and (user := galaxy_session.user):
return user
if api_user:
return api_user
raise UserRequiredException


class UrlBuilder:
def __init__(self, request: Request):
self.request = request
Expand Down Expand Up @@ -310,7 +322,7 @@ def set_cookie(
)


DependsOnUser = cast(Optional[User], Depends(get_user))
DependsOnUser = cast(User, Depends(get_required_user))


def get_current_history_from_session(galaxy_session: Optional[model.GalaxySession]) -> Optional[model.History]:
Expand Down Expand Up @@ -485,6 +497,7 @@ def cbv(self):

class Router(FrameworkRouter):
admin_user_dependency = AdminUserRequired
user_dependency = DependsOnUser


class APIContentTypeRoute(APIRoute):
Expand Down
12 changes: 8 additions & 4 deletions lib/galaxy/webapps/galaxy/api/file_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Response,
status,
)
from pydantic import UUID4

from galaxy.files.templates import FileSourceTemplateSummaries
from galaxy.managers.context import ProvidesUserContext
Expand All @@ -16,10 +17,12 @@
ModifyInstancePayload,
UserFileSourceModel,
)
from galaxy.model import User
from galaxy.util.config_templates import PluginStatus
from . import (
depends,
DependsOnTrans,
DependsOnUser,
Router,
)

Expand All @@ -28,14 +31,15 @@
router = Router(tags=["file_sources"])


UserFileSourceIdPathParam: str = Path(
UserFileSourceIdPathParam: UUID4 = Path(
..., title="User File Source UUID", description="The UUID index for a persisted UserFileSourceStore object."
)


@router.cbv
class FastAPIFileSources:
file_source_instances_manager: FileSourceInstancesManager = depends(FileSourceInstancesManager)
user: User = DependsOnUser

@router.get(
"/api/file_source_templates",
Expand Down Expand Up @@ -92,7 +96,7 @@ def instance_index(
def instances_show(
self,
trans: ProvidesUserContext = DependsOnTrans,
user_file_source_id: str = UserFileSourceIdPathParam,
user_file_source_id: UUID4 = UserFileSourceIdPathParam,
) -> UserFileSourceModel:
return self.file_source_instances_manager.show(trans, user_file_source_id)

Expand All @@ -104,7 +108,7 @@ def instances_show(
def update_instance(
self,
trans: ProvidesUserContext = DependsOnTrans,
user_file_source_id: str = UserFileSourceIdPathParam,
user_file_source_id: UUID4 = UserFileSourceIdPathParam,
payload: ModifyInstancePayload = Body(...),
) -> UserFileSourceModel:
return self.file_source_instances_manager.modify_instance(trans, user_file_source_id, payload)
Expand All @@ -118,7 +122,7 @@ def update_instance(
def purge_instance(
self,
trans: ProvidesUserContext = DependsOnTrans,
user_file_source_id: str = UserFileSourceIdPathParam,
user_file_source_id: UUID4 = UserFileSourceIdPathParam,
):
self.file_source_instances_manager.purge_instance(trans, user_file_source_id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
Loading

0 comments on commit 6e98bc8

Please sign in to comment.