diff --git a/src/videoag_common/__init__.py b/src/videoag_common/__init__.py index d75bae002c80f42534d4cf5008d797e4d870bdd3..56bc2e612bb57dc3b519061af457532f43662207 100644 --- a/src/videoag_common/__init__.py +++ b/src/videoag_common/__init__.py @@ -1,13 +1,14 @@ import os from pathlib import Path -from videoag_common.miscellaneous.util import load_config_file, merge_config_with +from videoag_common.miscellaneous.util import load_config_file, merge_config_into if "VIDEOAG_CONFIG" not in os.environ: raise Exception("Missing VIDEOAG_CONFIG environment variable") config = load_config_file(Path(os.getcwd()).joinpath(os.environ["VIDEOAG_CONFIG"])) if "VIDEOAG_TEST_CONFIG_OVERRIDE" in os.environ: - merge_config_with( + merge_config_into( config, - load_config_file(Path(os.getcwd()).joinpath(os.environ["VIDEOAG_TEST_CONFIG_OVERRIDE"])) + load_config_file(Path(os.getcwd()).joinpath(os.environ["VIDEOAG_TEST_CONFIG_OVERRIDE"])), + overwrite_non_mergeable=True ) diff --git a/src/videoag_common/miscellaneous/util.py b/src/videoag_common/miscellaneous/util.py index 041325c524b6a5e55690895708e2971bc38f1906..54c50b108834638290c821c75ec48239388b3ab3 100644 --- a/src/videoag_common/miscellaneous/util.py +++ b/src/videoag_common/miscellaneous/util.py @@ -114,12 +114,12 @@ def load_config_file(path: Path): return config -def merge_config_with(config: dict, to_merge: dict, overwrite_non_mergeable: bool = False): +def merge_config_into(config: dict, to_merge: dict, overwrite_non_mergeable: bool = False): for key, item in to_merge.items(): if key not in config: config[key] = item elif isinstance(item, dict) and isinstance(config[key], dict): - merge_config_with(config[key], item) + merge_config_into(config[key], item, overwrite_non_mergeable=overwrite_non_mergeable) elif overwrite_non_mergeable: config[key] = item else: diff --git a/src/videoag_common/objects/__init__.py b/src/videoag_common/objects/__init__.py index 5e6d4b4e166b051711dde586c74dcbf6979b610d..373c8c8f8b2163727f987c4b450b18c0ad46d6e9 100644 --- a/src/videoag_common/objects/__init__.py +++ b/src/videoag_common/objects/__init__.py @@ -20,6 +20,7 @@ from .medium import ( ThumbnailTargetMedium, SourceMedium, SourceMediumStatus, + MediaProcessTemplate, LOAD_SOURCE_MEDIUM_LECTURE, LOAD_PUBLISH_MEDIUM_LECTURE, LOAD_PUBLISH_MEDIUM_TARGET_MEDIUM, diff --git a/src/videoag_common/objects/changelog.py b/src/videoag_common/objects/changelog.py index ae3bafccf2801ab4ab6b230e3641c72ee4309a7b..a575ea96c5338e8e8c1beb383d6cfe110a68affa 100644 --- a/src/videoag_common/objects/changelog.py +++ b/src/videoag_common/objects/changelog.py @@ -88,7 +88,8 @@ class ChangelogModificationEntry(ChangelogEntry): old_value: Mapped[dict] = api_mapped( mapped_column(sql.types.JSON(), nullable=True), ApiJsonField( - include_in_data=True, data_notes="Note that this may contain arbitrary json due to legacy values" + include_in_data=True, data_if=lambda entry, args: entry.old_value is not None, + data_notes="Note that this may contain arbitrary json due to legacy values. Not present if this was at creation" ) ) new_value: Mapped[dict] = api_mapped( diff --git a/src/videoag_common/objects/course.py b/src/videoag_common/objects/course.py index 5f08fdefaa59a60ec4dc4055edf3b43cae227e6a..fa9629bd42f28f6572e0ac2ccca82087097eee33 100644 --- a/src/videoag_common/objects/course.py +++ b/src/videoag_common/objects/course.py @@ -134,7 +134,7 @@ class Lecture(DeletableApiObject, VisibilityApiObject, ApiViewPermissionsObject, publish_time: Mapped[datetime] = api_mapped( mapped_column(TIMESTAMP(), nullable=True, index=True), ApiDatetimeField( - include_in_data=True + include_in_data=True, data_only_mod=True ) ) media_process: Mapped[dict] = api_mapped( @@ -467,11 +467,13 @@ class Course(DeletableApiObject, VisibilityApiObject, ApiViewPermissionsObject, lectures: Mapped[list[Lecture]] = relationship( back_populates="course", primaryjoin=lambda: sql.and_(Lecture.course_id == Course.id, Lecture.has_access(is_mod=True, from_course=True)), + order_by=Lecture.time.asc(), lazy="raise_on_sql" ) public_lectures: Mapped[list[Lecture]] = relationship( back_populates="course", primaryjoin=lambda: sql.and_(Lecture.course_id == Course.id, Lecture.has_access(is_mod=False, from_course=True)), + order_by=Lecture.time.asc(), lazy="raise_on_sql", viewonly=True ) @@ -492,7 +494,8 @@ class Course(DeletableApiObject, VisibilityApiObject, ApiViewPermissionsObject, type_id="lecture[]", data_id="lectures", data_if=lambda course, args: args.include_lectures, - data_notes="Only present if requested. All (public) lectures. Lectures will include chapters and media_sources" + data_notes="Only present if requested. All (public) lectures. Sorted by their time ascending. Lectures will " + "include chapters and publish media" ) def _data_lectures(self, is_mod: bool): return self.lectures if is_mod else self.public_lectures diff --git a/src/videoag_common/objects/medium.py b/src/videoag_common/objects/medium.py index b103c62ce967f385cd7d7118ff7821082514c2ab..2bdb82b3fbe24ac9aa74933a1e8ed96ce685aaee 100644 --- a/src/videoag_common/objects/medium.py +++ b/src/videoag_common/objects/medium.py @@ -558,13 +558,15 @@ class MediaProcessTemplate(ApiObject, Base): mapped_column(String(collation=STRING_COLLATION), nullable=False), ApiStringField( max_length=256, - include_in_config=True + include_in_config=True, config_directly_modifiable=True, + include_in_data=True ) ) process: Mapped[dict] = api_mapped( mapped_column(postgresql.JSONB, nullable=False), ApiMediaProcessField( - include_in_config=True + include_in_config=True, config_directly_modifiable=True, + include_in_data=True ) )