Skip to content

Commit

Permalink
Merge pull request galaxyproject#18792 from arash77/update-fastapi-viz
Browse files Browse the repository at this point in the history
Update Visualization FastAPI
  • Loading branch information
mvdbeek authored Sep 11, 2024
2 parents 0d4cb10 + 8daf740 commit a79a132
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 59 deletions.
15 changes: 3 additions & 12 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4689,11 +4689,8 @@ export interface paths {
put?: never;
/**
* Create a new visualization.
* @description POST /api/visualizations
* creates a new visualization using the given payload and does not require the import_id field
*
* POST /api/visualizations?import_id={encoded_visualization_id}
* imports a copy of an existing visualization into the user's workspace and does not require the rest of the payload
* @description Creates a new visualization using the given payload and does not require the import_id field.
* If import_id given, it imports a copy of an existing visualization into the user's workspace and does not require the rest of the payload.
*/
post: operations["create_api_visualizations_post"];
delete?: never;
Expand Down Expand Up @@ -16850,12 +16847,6 @@ export interface components {
* @description The database key of the visualization.
*/
dbkey?: string | null;
/**
* Save
* @description Whether to save the visualization.
* @default true
*/
save: boolean | null;
/**
* Slug
* @description The slug of the visualization.
Expand All @@ -16871,7 +16862,7 @@ export interface components {
* Type
* @description The type of the visualization.
*/
type?: string | null;
type: string;
};
/** VisualizationCreateResponse */
VisualizationCreateResponse: {
Expand Down
10 changes: 3 additions & 7 deletions lib/galaxy/schema/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,15 +298,16 @@ class VisualizationUpdateResponse(Model):


class VisualizationCreatePayload(Model):
type: Optional[SanitizedString] = Field(
None,
type: str = Field(
...,
title="Type",
description="The type of the visualization.",
)
title: Optional[SanitizedString] = Field(
SanitizedString("Untitled Visualization"),
title="Title",
description="The name of the visualization.",
min_length=3,
)
dbkey: Optional[SanitizedString] = Field(
None,
Expand All @@ -328,11 +329,6 @@ class VisualizationCreatePayload(Model):
title="Config",
description="The config of the visualization.",
)
save: Optional[bool] = Field(
True,
title="Save",
description="Whether to save the visualization.",
)


class VisualizationUpdatePayload(Model):
Expand Down
7 changes: 2 additions & 5 deletions lib/galaxy/webapps/galaxy/api/visualizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,8 @@ def create(
trans: ProvidesUserContext = DependsOnTrans,
) -> VisualizationCreateResponse:
"""
POST /api/visualizations
creates a new visualization using the given payload and does not require the import_id field
POST /api/visualizations?import_id={encoded_visualization_id}
imports a copy of an existing visualization into the user's workspace and does not require the rest of the payload
Creates a new visualization using the given payload and does not require the import_id field.
If import_id given, it imports a copy of an existing visualization into the user's workspace and does not require the rest of the payload.
"""
return self.service.create(trans, import_id, payload)

Expand Down
57 changes: 22 additions & 35 deletions lib/galaxy/webapps/galaxy/services/visualizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
from galaxy.security.idencoding import IdEncodingHelper
from galaxy.structured_app import StructuredApp
from galaxy.util.hash_util import md5_hash_str
from galaxy.util.sanitize_html import sanitize_html
from galaxy.visualization.plugins.plugin import VisualizationPlugin
from galaxy.visualization.plugins.registry import VisualizationsRegistry
from galaxy.web import url_for
Expand Down Expand Up @@ -163,29 +162,24 @@ def create(
if import_id:
visualization = self._import_visualization(trans, import_id)
else:
# must have a type (I've taken this to be the visualization name)
if not payload.type:
raise exceptions.RequestParameterMissingException("key/value 'type' is required")
type = payload.type
title = payload.title
slug = payload.slug
dbkey = payload.dbkey
annotation = payload.annotation
config = payload.config
save = payload.save

# generate defaults - this will err if given a weird key?
visualization = self._create_visualization(trans, type, title, dbkey, slug, annotation, save)
visualization = self._create_visualization(trans, type, title, dbkey, slug, annotation)

# Create and save first visualization revision
revision = VisualizationRevision(visualization=visualization, title=title, config=config, dbkey=dbkey)
visualization.latest_revision = revision

if save:
session = trans.sa_session
session.add(revision)
with transaction(session):
session.commit()
session = trans.sa_session
session.add(revision)
with transaction(session):
session.commit()

return VisualizationCreateResponse(id=str(visualization.id))

Expand Down Expand Up @@ -245,10 +239,7 @@ def _get_visualization(
"""
Get a Visualization from the database by id, verifying ownership.
"""
try:
visualization = trans.sa_session.get(Visualization, visualization_id)
except TypeError:
visualization = None
visualization = trans.sa_session.get(Visualization, visualization_id)
if not visualization:
raise exceptions.ObjectNotFound("Visualization not found")
else:
Expand Down Expand Up @@ -300,28 +291,26 @@ def _create_visualization(
self,
trans: ProvidesUserContext,
type: str,
title: Optional[str] = None,
title: Optional[str] = "Untitled Visualization",
dbkey: Optional[str] = None,
slug: Optional[str] = None,
annotation: Optional[str] = None,
save: Optional[bool] = True,
) -> Visualization:
"""Create visualization but not first revision. Returns Visualization object."""
user = trans.get_user()

# Error checking.
title_err = slug_err = ""
if not title:
title_err = "visualization name is required"
elif slug and not is_valid_slug(slug):
slug_err = "visualization identifier must consist of only lowercase letters, numbers, and the '-' character"
elif slug and slug_exists(trans.sa_session, Visualization, user, slug, ignore_deleted=True):
slug_err = "visualization identifier must be unique"

if title_err or slug_err:
# TODO: handle this error structure better
val_err = str(title_err or slug_err)
raise exceptions.RequestParameterMissingException(val_err)
if slug:
slug_err = ""
if not is_valid_slug(slug):
slug_err = (
"visualization identifier must consist of only lowercase letters, numbers, and the '-' character"
)
elif slug_exists(trans.sa_session, Visualization, user, slug, ignore_deleted=True):
slug_err = "visualization identifier must be unique"
if slug_err:
# TODO: handle this error structure better
raise exceptions.RequestParameterMissingException(slug_err)

# Create visualization
visualization = Visualization(user=user, title=title, dbkey=dbkey, type=type)
Expand All @@ -331,16 +320,14 @@ def _create_visualization(
slug_builder = SlugBuilder()
slug_builder.create_item_slug(trans.sa_session, visualization)
if annotation:
annotation = sanitize_html(annotation)
# TODO: if this is to stay in the mixin, UsesAnnotations should be added to the superclasses
# right now this is depending on the classes that include this mixin to have UsesAnnotations
add_item_annotation(trans.sa_session, trans.user, visualization, annotation)

if save:
session = trans.sa_session
session.add(visualization)
with transaction(session):
session.commit()
session = trans.sa_session
session.add(visualization)
with transaction(session):
session.commit()

return visualization

Expand Down

0 comments on commit a79a132

Please sign in to comment.