diff --git a/api/api_specification.json b/api/api_specification.json index c9dc81f5c6959f6e483f60992de67b7e44268038..5dd606c02d7c1a9c883648d909661f4ae9ec3abd 100644 --- a/api/api_specification.json +++ b/api/api_specification.json @@ -3888,14 +3888,14 @@ "publish_medium": { "fields": { "": { - "allow_download": { + "download_url": { "config_directly_modifiable": false, - "id": "allow_download", - "notes": "If true, this medium might be downloaded", + "id": "download_url", + "notes": "URL where the medium can be downloaded. If not present, the medium may not be downloaded", "object_variant": null, "only_mod": false, - "optional": false, - "type": "boolean" + "optional": true, + "type": "string" }, "id": { "config_directly_modifiable": false, diff --git a/api/api_specification.md b/api/api_specification.md index 3be120b485e5913db752aaae3b1a32a7255b435c..f6433b828c84bab383d988df9d4c945d156d2834 100644 --- a/api/api_specification.md +++ b/api/api_specification.md @@ -1,4 +1,4 @@ -# Specification of the Web API for the Video-AG Website (v0.81). +# Specification of the Web API for the Video-AG Website (v0.82). ## Introduction @@ -2809,9 +2809,9 @@ Additionally, the following objects may appear as the type of some field: </thead> <tbody> <tr> - <td>allow_download</td> - <td>boolean</td> - <td>If true, this medium might be downloaded</td> + <td>download_url</td> + <td>?string</td> + <td>URL where the medium can be downloaded. If not present, the medium may not be downloaded</td> </tr> <tr> <td>id</td> @@ -3188,6 +3188,12 @@ Possible `error_code`: ## Changelog +### v0.82 + +* Changed `publish_medium` + * Removed field `allow_download` + * Added field `download_url` + ### v0.81 * Added milliseconds to `datetime` type and clarified that it is in UTC. diff --git a/api/api_specification_template.md b/api/api_specification_template.md index 5b45245f9d0126639743c5c80df0e53f10eb37fa..03f847cae26fd486c562576fb1daf96f6772a0c4 100644 --- a/api/api_specification_template.md +++ b/api/api_specification_template.md @@ -1,4 +1,4 @@ -# Specification of the Web API for the Video-AG Website (v0.81). +# Specification of the Web API for the Video-AG Website (v0.82). ## Introduction @@ -139,6 +139,12 @@ Possible `error_code`: ## Changelog +### v0.82 + +* Changed `publish_medium` + * Removed field `allow_download` + * Added field `download_url` + ### v0.81 * Added milliseconds to `datetime` type and clarified that it is in UTC. diff --git a/api/src/api/routes/resources.py b/api/src/api/routes/resources.py index a54caaf26ed4365f5b49cd1b98bccd260d82a4e2..8e0ce296e896f535c7d35e1786d4fd0b2068606a 100644 --- a/api/src/api/routes/resources.py +++ b/api/src/api/routes/resources.py @@ -57,8 +57,10 @@ def _decode_str_from_url(url_val: str) -> str: @api_route("/course/<string:course_handle>/resources/medium_file/<int:medium_file_id>", "GET", allow_while_readonly=True, no_documentation=True) def api_route_access_target_medium(course_handle: str, medium_file_id: int): + download = request.args.get("download", "true").lower() == "true" medium_file = _check_access_medium_file(course_handle, medium_file_id) - return redirect(f"{_FILE_URI_PREFIX}/{medium_file.file_path}?co_ha={_encode_str_for_url(course_handle)}&mf_id={medium_file.id}") + # TODO download stats + return redirect(f"{_FILE_URI_PREFIX}/{medium_file.file_path}?co_ha={_encode_str_for_url(course_handle)}&mf_id={medium_file.id}&download={"true" if download else "false"}") @api_route("/resources/internal_auth_check", "GET", allow_while_readonly=True, diff --git a/common_py/src/videoag_common/objects/medium.py b/common_py/src/videoag_common/objects/medium.py index 6f90637f8227a55d4aec8790a05b0d577052a459..52a539c0db255e26111b4fd00a428f9706392c49 100644 --- a/common_py/src/videoag_common/objects/medium.py +++ b/common_py/src/videoag_common/objects/medium.py @@ -405,6 +405,13 @@ class PublishMedium(VisibilityApiObject, DeletableApiObject, Base): def url(self) -> str: return f"{_API_BASE_URL}/course/{self.lecture.course.handle}/resources/medium_file/{self.medium_metadata.file.id}" + @api_include_in_data( + data_notes="URL where the medium can be downloaded. If not present, the medium may not be downloaded", + data_if=lambda medium, args: medium.medium_metadata.can_download() and (args.is_mod or medium.lecture.course.allow_download) + ) + def download_url(self) -> str: + return f"{_API_BASE_URL}/course/{self.lecture.course.handle}/resources/medium_file/{self.medium_metadata.file.id}?download=true" + @api_include_in_data( data_notes="If true, this medium might be shown with the player. Otherwise, the player should ignore it because" " it is only intended for download, etc." @@ -412,13 +419,6 @@ class PublishMedium(VisibilityApiObject, DeletableApiObject, Base): def include_in_player(self) -> bool: return self.medium_metadata.can_include_in_player() - @api_include_in_data( - data_notes="If true, this medium might be downloaded" - ) - def allow_download(self, is_mod: bool) -> bool: - return (self.medium_metadata.can_download() - and (is_mod or self.lecture.course.allow_download)) - @hybrid_method def has_access(self, context: dict[AccessContextKey, Any]): cond = super().has_access(context) diff --git a/common_py/src/videoag_common/test/object_data.py b/common_py/src/videoag_common/test/object_data.py index d3d6bb6996d9bcb6a8db4841d5d838a90587dd6e..1d768076ba67cea46620fa12dc9ffe7537f95db8 100644 --- a/common_py/src/videoag_common/test/object_data.py +++ b/common_py/src/videoag_common/test/object_data.py @@ -303,7 +303,7 @@ TEST_DATA_PUBLISH_MEDIUM_186 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_15, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/5", - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/5?download=true", "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_186_MOD = TEST_DATA_PUBLISH_MEDIUM_186 | \ @@ -317,7 +317,7 @@ TEST_DATA_PUBLISH_MEDIUM_204 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_16, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/9", - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/9?download=true", "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_204_MOD = TEST_DATA_PUBLISH_MEDIUM_204 | \ @@ -331,7 +331,7 @@ TEST_DATA_PUBLISH_MEDIUM_1368 = \ "title": "Super video!", "medium_metadata": TEST_DATA_MEDIUM_METADATA_5, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-buk/resources/medium_file/6", - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-buk/resources/medium_file/6?download=true", "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_1368_MOD = TEST_DATA_PUBLISH_MEDIUM_1368 | \ @@ -345,7 +345,7 @@ TEST_DATA_PUBLISH_MEDIUM_1495 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_7, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-diskrete/resources/medium_file/7", - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-diskrete/resources/medium_file/7?download=true", "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_1495_MOD = TEST_DATA_PUBLISH_MEDIUM_1495 | \ @@ -359,13 +359,12 @@ TEST_DATA_PUBLISH_MEDIUM_1497 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_19, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/11ws-infin/resources/medium_file/8", - "allow_download": False, "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_1497_MOD = TEST_DATA_PUBLISH_MEDIUM_1497 | \ { "visible": True, - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/11ws-infin/resources/medium_file/8?download=true", } TEST_DATA_PUBLISH_MEDIUM_100003 = \ @@ -374,7 +373,6 @@ TEST_DATA_PUBLISH_MEDIUM_100003 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_6, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-buk/resources/medium_file/1", - "allow_download": False, "include_in_player": False, } TEST_DATA_PUBLISH_MEDIUM_100003_MOD = TEST_DATA_PUBLISH_MEDIUM_100003 | \ @@ -388,7 +386,6 @@ TEST_DATA_PUBLISH_MEDIUM_100025 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_8, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/07ws-diskrete/resources/medium_file/2", - "allow_download": False, "include_in_player": False, } TEST_DATA_PUBLISH_MEDIUM_100025_MOD = TEST_DATA_PUBLISH_MEDIUM_100025 | \ @@ -402,7 +399,6 @@ TEST_DATA_PUBLISH_MEDIUM_100186 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_17, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/3", - "allow_download": False, "include_in_player": False, } TEST_DATA_PUBLISH_MEDIUM_100186_MOD = TEST_DATA_PUBLISH_MEDIUM_100186 | \ @@ -416,7 +412,6 @@ TEST_DATA_PUBLISH_MEDIUM_101186 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_20, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/11ws-infin/resources/medium_file/4", - "allow_download": False, "include_in_player": False, } TEST_DATA_PUBLISH_MEDIUM_101186_MOD = TEST_DATA_PUBLISH_MEDIUM_101186 | \ @@ -430,7 +425,7 @@ TEST_DATA_PUBLISH_MEDIUM_101189 = \ "title": "", "medium_metadata": TEST_DATA_MEDIUM_METADATA_25, "url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/10", - "allow_download": True, + "download_url": "https://api.video.fsmpi.rwth-aachen.de/api/v0/course/09ss-fosap/resources/medium_file/10?download=true", "include_in_player": True, } TEST_DATA_PUBLISH_MEDIUM_101189_MOD = TEST_DATA_PUBLISH_MEDIUM_101189 | \