diff --git a/bioimageio_collection_backoffice/collection_json.py b/bioimageio_collection_backoffice/collection_json.py index 366b513d..312c1b29 100644 --- a/bioimageio_collection_backoffice/collection_json.py +++ b/bioimageio_collection_backoffice/collection_json.py @@ -11,6 +11,7 @@ CollectionWebsiteConfigTemplate, ) from .common import Node +from .db_structure.version_info import DraftStatus, ErrorStatus class Author(Node, frozen=True): @@ -30,8 +31,14 @@ class TrainingData(Node, frozen=True): id: str +class Uploader(Node, frozen=True): + name: Optional[str] = None + email: str + + class CollectionEntry(Node, frozen=True): authors: Sequence[Author] + uploader: Uploader badges: Sequence[Badge] concept_doi: Optional[str] covers: Sequence[HttpUrl] @@ -52,6 +59,8 @@ class CollectionEntry(Node, frozen=True): training_data: Optional[TrainingData] = None type: Literal["application", "model", "notebook", "dataset"] source: Optional[str] = None + status: Optional[Union[DraftStatus, ErrorStatus]] = None + """status of the draft (for collection_draft.json only)""" def __lt__(self, other: CollectionEntry): sdc = 0 if self.download_count == "?" else self.download_count diff --git a/bioimageio_collection_backoffice/mailroom/send_email.py b/bioimageio_collection_backoffice/mailroom/send_email.py index 46b8a58e..622db390 100644 --- a/bioimageio_collection_backoffice/mailroom/send_email.py +++ b/bioimageio_collection_backoffice/mailroom/send_email.py @@ -17,19 +17,17 @@ def notify_uploader(rv: Union[RecordDraft, Record], subject_end: str, msg: str): - email, name = rv.get_uploader() - if email is None: - raise ValueError("missing uploader email") + uploader = rv.get_uploader() subject = f"{STATUS_UPDATE_SUBJECT}{rv.id} {rv.version} {subject_end.strip()}" - if email == BOT_EMAIL: + if uploader.email == BOT_EMAIL: logger.info("skipping email '{}' to {}", subject, BOT_EMAIL) return send_email( subject=subject, body=( - f"Dear {name},\n" + f"Dear {uploader.name},\n" + f"{msg.strip()}\n" + "Kind regards,\n" + "The bioimage.io bot 🦒\n" @@ -37,7 +35,7 @@ def notify_uploader(rv: Union[RecordDraft, Record], subject_end: str, msg: str): ).replace( "\n", "\n\n" # respect newlines in markdown ), - recipients=[email], + recipients=[uploader.email], ) diff --git a/bioimageio_collection_backoffice/remote_collection.py b/bioimageio_collection_backoffice/remote_collection.py index df657e57..ebdcc508 100644 --- a/bioimageio_collection_backoffice/remote_collection.py +++ b/bioimageio_collection_backoffice/remote_collection.py @@ -19,7 +19,6 @@ List, Literal, Mapping, - NamedTuple, Optional, Sequence, Tuple, @@ -38,7 +37,7 @@ from loguru import logger from pydantic import AnyUrl from ruyaml import YAML -from typing_extensions import Concatenate, ParamSpec +from typing_extensions import Concatenate, ParamSpec, assert_never from ._settings import settings from ._thumbnails import create_thumbnails @@ -50,6 +49,7 @@ CollectionWebsiteConfig, ConceptSummary, ConceptVersion, + Uploader, ) from .db_structure.chat import Chat, Message from .db_structure.compatibility import ( @@ -569,11 +569,6 @@ def doi(self): return None -class Uploader(NamedTuple): - email: Optional[str] - name: str - - @dataclass class RecordBase(RemoteBase, ABC): """Base class for a `RecordDraft` and `Record`""" @@ -633,18 +628,7 @@ def extend_chat( def get_uploader(self): rdf = self.get_rdf() - try: - uploader = rdf["uploader"] - email = uploader["email"] - name = uploader.get( - "name", f"{rdf.get('type', 'bioimage.io resource')} contributor" - ) - except Exception as e: - logger.error("failed to extract uploader from rdf: {}", e) - email = None - name = "bioimage.io resource contributor" - - return Uploader(email=email, name=name) + return Uploader.model_validate(rdf["uploader"]) def get_file_url(self, path: str): return self.client.get_file_url(f"{self.folder}files/{path}") @@ -1193,6 +1177,11 @@ def create_collection_entries( f"{record_version.concept.folder}versions.json", versions_info.model_dump(mode="json"), ) + status = None + elif isinstance(record_version, RecordDraft): + status = record_version.info.status + else: + assert_never(record_version) try: # legacy nickname @@ -1261,6 +1250,7 @@ def get_compat_tag(tool: str): return [ CollectionEntry( authors=rdf.get("authors", []), + uploader=rdf["uploader"], badges=resolve_relative_path( maybe_swap_with_thumbnail(rdf.get("badges", []), thumbnails), parsed_root, @@ -1289,5 +1279,6 @@ def get_compat_tag(tool: str): training_data=rdf["training_data"] if "training_data" in rdf else None, type=rdf["type"], source=rdf.get("source"), + status=status, ) ], id_map