From d35a1839ad2c8ee30bdbded88a304450442b02f2 Mon Sep 17 00:00:00 2001 From: mike seibel Date: Fri, 14 Jun 2024 15:21:27 -0700 Subject: [PATCH] folder mgmt with context, push/post session requires valid folder id --- docker-compose.yml | 1 + docker/settings.py | 5 +- scheduler/course.py | 7 -- scheduler/dao/canvas.py | 11 ++- scheduler/dao/panopto/__init__.py | 2 - scheduler/dao/panopto/sessions.py | 13 +++ scheduler/dao/sws.py | 8 +- scheduler/exceptions.py | 4 + scheduler/org/uw/course.py | 84 ++++++++++++++----- .../4D636EED27CE9A2EACAD798E82C139BF | 1 + .../DAEB0FCDD492D3F8A120619D33A96D09 | 2 +- .../6298A683FA88F4AC8518436715C5A45A | 1 + .../0E33841B3F905C740C82794EC9920C48 | 2 +- .../4B8FDE6E65F308A114DF5C05EFE1BA31 | 2 +- .../8B4EF0CEB260E300112EDBF5EF4EE5A6 | 2 +- .../EE5BF1A43C87AC958B88856CA5494F10 | 2 +- scheduler/schedule.py | 8 +- scheduler/test/api/test_session.py | 2 +- .../test/test_location_and_recordings.py | 2 +- scheduler/utils/__init__.py | 4 + scheduler/utils/recorder.py | 4 - scheduler/utils/session.py | 18 ---- scheduler/views/api/session.py | 61 ++++---------- setup.py | 2 + 24 files changed, 132 insertions(+), 116 deletions(-) create mode 100644 scheduler/resources/panopto/file/BasicHttpBinding_IRemoteRecorderManagement/ScheduleRecording/4D636EED27CE9A2EACAD798E82C139BF create mode 100644 scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersWithExternalContextByExternalId/6298A683FA88F4AC8518436715C5A45A delete mode 100644 scheduler/utils/session.py diff --git a/docker-compose.yml b/docker-compose.yml index 63c485d..426a9ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,7 @@ services: ENV: localdev PORT: 8000 AUTH: SAML_MOCK BLTI_DEV + PANOPTO_API_APP_ID: UWNetid LTI_DEVELOP_APP: scheduler/course restart: always container_name: app-scheduler diff --git a/docker/settings.py b/docker/settings.py index a14d0cc..d8b09f9 100644 --- a/docker/settings.py +++ b/docker/settings.py @@ -95,12 +95,13 @@ 'is_desktop': True, } +PANOPTO_API_USER = os.getenv('PANOPTO_API_USER', '') +PANOPTO_API_APP_ID = os.getenv('PANOPTO_API_APP_ID', '') + if os.getenv("ENV", "localdev") == "localdev": LTI_DEVELOP_APP = os.getenv("LTI_DEVELOP_APP", '') DEBUG = True else: - PANOPTO_API_USER = os.getenv('PANOPTO_API_USER') - PANOPTO_API_APP_ID = os.getenv('PANOPTO_API_APP_ID') PANOPTO_API_TOKEN = os.getenv('PANOPTO_API_TOKEN') PANOPTO_SERVER = os.getenv('PANOPTO_SERVER') DEBUG = (os.getenv("ENV", "UNSET") == "dev") diff --git a/scheduler/course.py b/scheduler/course.py index 01c1d45..b2a1233 100644 --- a/scheduler/course.py +++ b/scheduler/course.py @@ -36,13 +36,6 @@ def reservation_uid(self): """ pass - @abstractmethod - def canvas_sis_id(self): - """Canvas SIS_ID assigned to a Canvas course by Student - system provisioning process - """ - pass - @abstractmethod def panopto_course_external_id(self, start_datetime): """Opaque string unique to each course offering.""" diff --git a/scheduler/dao/canvas.py b/scheduler/dao/canvas.py index cba5ea7..0660f09 100644 --- a/scheduler/dao/canvas.py +++ b/scheduler/dao/canvas.py @@ -4,5 +4,14 @@ from uw_canvas.courses import Courses as CanvasCourses +canvas_api = CanvasCourses() + def get_course_by_sis_id(sis_id): - return CanvasCourses().get_course_by_sis_id(sis_id) + return canvas_api.get_course_by_sis_id(sis_id) + + +def get_course_by_canvas_id(course_id): + if canvas_api.valid_course_id(course_id): + return canvas_api.get_course(course_id) + + raise Exception("Invalid course id: {}".format(course_id)) diff --git a/scheduler/dao/panopto/__init__.py b/scheduler/dao/panopto/__init__.py index 77418e5..e69de29 100644 --- a/scheduler/dao/panopto/__init__.py +++ b/scheduler/dao/panopto/__init__.py @@ -1,2 +0,0 @@ -# Copyright 2023 UW-IT, University of Washington -# SPDX-License-Identifier: Apache-2.0 diff --git a/scheduler/dao/panopto/sessions.py b/scheduler/dao/panopto/sessions.py index e38c1a5..f841c69 100644 --- a/scheduler/dao/panopto/sessions.py +++ b/scheduler/dao/panopto/sessions.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 from panopto_client.session import SessionManagement +from scheduler.utils import panopto_app_id session_api = SessionManagement() @@ -39,6 +40,14 @@ def get_folders_list(*args, **kwargs): return session_api.getFoldersList(*args, **kwargs) +def get_all_folders_with_external_context_list(external_ids, providers=None): + if not providers: + providers = [panopto_app_id()] + + return session_api.getAllFoldersWithExternalContextByExternalId( + external_ids, providers) + + def get_all_folders_by_external_id(external_ids): return session_api.getAllFoldersByExternalId(external_ids) @@ -47,6 +56,10 @@ def add_folder(name): return session_api.addFolder(name) +def provision_external_course(course_name, external_id): + return session_api.provisionExternalCourse(course_name, external_id) + + def update_folder_external_id_with_provider(folder_id, external_id, provider): return session_api.updateFolderExternalIdWithProvider( folder_id, external_id, provider) diff --git a/scheduler/dao/sws.py b/scheduler/dao/sws.py index b915748..83823c8 100644 --- a/scheduler/dao/sws.py +++ b/scheduler/dao/sws.py @@ -4,9 +4,15 @@ from uw_sws.section import get_section_by_label, get_section_by_url +def sws_course_label(course): + return "{},{},{},{}/{}".format(course.year, course.quarter, + course.curriculum, course.number, + course.section) + + def get_sws_section_for_course(course): return get_section_by_label( - course.sws_course_label(), + sws_course_label(course), include_instructor_not_on_time_schedule=False) diff --git a/scheduler/exceptions.py b/scheduler/exceptions.py index a6d86ca..96550b8 100644 --- a/scheduler/exceptions.py +++ b/scheduler/exceptions.py @@ -39,3 +39,7 @@ class ValidationException(Exception): class PanoptoUserException(Exception): pass + + +class PanoptoFolderDoesNotExist(Exception): + pass diff --git a/scheduler/org/uw/course.py b/scheduler/org/uw/course.py index 4e77c63..26d1b41 100644 --- a/scheduler/org/uw/course.py +++ b/scheduler/org/uw/course.py @@ -5,10 +5,13 @@ from scheduler.models import Curriculum from scheduler.utils import local_ymd_from_utc_date_string from scheduler.dao.canvas import get_course_by_sis_id +from scheduler.dao.panopto.sessions import ( + get_all_folders_with_external_context_list, provision_external_course) from scheduler.dao.sws import ( get_sws_section_for_course, get_sws_section_by_url) from scheduler.exceptions import ( - MissingParamException, InvalidParamException) + MissingParamException, InvalidParamException, PanoptoFolderDoesNotExist) + from restclients_core.exceptions import DataFailureException from dateutil import parser from nameparser import HumanName @@ -26,6 +29,7 @@ class Course(BaseCourse): number = "" section = "" external_id = "" + canvas_course_id = None UW_CAMPUS = ['seattle', 'bothell', 'tacoma'] UW_TERMS = ['spring', 'summer', 'autumn', 'winter'] @@ -81,11 +85,6 @@ def reservation_uid(self): self.curriculum.replace(' ', ''), self.number, self.section) - def sws_course_label(self): - return "{},{},{},{}/{}".format(self.year, self.quarter, - self.curriculum, self.number, - self.section) - def canvas_sis_id(self): return "{}".format('-'.join([ self.year, self.quarter, self.curriculum, @@ -99,28 +98,67 @@ def panopto_course_external_id(self, start_datetime): self.year, self.quarter, self.curriculum, self.number, self.section, start_date) - def panopto_course_folder(self, title): - quarter_initial = self.quarter[0:1].upper() - quarter_lower = self.quarter[1:] - folder_prefix = "{}{} {} - ".format( - quarter_initial, quarter_lower, self.year) + def canvas_course(self): + if self.canvas_course_id is None: + try: + return get_course_by_sis_id(self.canvas_sis_id()) + except DataFailureException as ex: + raise DataFailureException( + ex.url, 404 if ex.status == 404 else 424, + "course_id fetch: {}".format(ex)) + + return self.canvas_course_id + + def panopto_course_folder(self): + canvas_course = self.canvas_course() try: - # folder id needs to match canvas course id - canvas_course = get_course_by_sis_id(self.canvas_sis_id()) - external_id = str(canvas_course.course_id) - folder = canvas_course.name - except Exception as ex: - logger.exception(ex) - external_id = None - folder = "{} {} {} {}{} {}: {}".format( - self.curriculum, self.number, self.section, quarter_initial, - quarter_lower[:1], str(self.year)[2:], title.title()) + panopto_folder = self._panopto_folder_from_course_id( + str(canvas_course.course_id)) + except PanoptoFolderDoesNotExist: + panopto_folder = self._create_panopto_folder(canvas_course) return { - 'name': "{}{}".format(folder_prefix, folder), - 'external_id': external_id + 'name': panopto_folder.Name, + 'id': panopto_folder.Id } + def _panopto_folder_from_course_id(self, course_id): + if course_id: + folders = get_all_folders_with_external_context_list([course_id]) + if folders: + if len(folders) == 1: + if len(folders[0]) == 1: + return folders[0][0] + else: + self._bad_folder_response(len(folders[0]), course_id) + else: + self._bad_folder_response(len(folders), course_id) + + raise PanoptoFolderDoesNotExist() + + def _bad_folder_response(self, folder_count, course_id): + message = 'Unexpected folder count {} for {}'.format( + folder_count, course_id) + logger.error(message) + raise DataFailureException("", 424, message) + + def _create_panopto_folder(self, canvas_course): + try: + folder = provision_external_course( + self.panopto_folder_name(canvas_course.name), + str(canvas_course.course_id)) + if folder: + return folder + + raise DataFailureException('', 424, 'folder provision failed') + except DataFailureException as ex: + raise DataFailureException( + ex.url, 424, "folder provision: {}".format(ex)) + + def panopto_folder_name(self, course_name): + return "{} {} - ".format( + self.quarter.capitalize(), self.year, course_name) + def panopto_course_session(self, start_datetime): name = "{} {} {} - {}".format( self.curriculum, self.number, self.section, diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_IRemoteRecorderManagement/ScheduleRecording/4D636EED27CE9A2EACAD798E82C139BF b/scheduler/resources/panopto/file/BasicHttpBinding_IRemoteRecorderManagement/ScheduleRecording/4D636EED27CE9A2EACAD798E82C139BF new file mode 100644 index 0000000..d265694 --- /dev/null +++ b/scheduler/resources/panopto/file/BasicHttpBinding_IRemoteRecorderManagement/ScheduleRecording/4D636EED27CE9A2EACAD798E82C139BF @@ -0,0 +1 @@ +false23012340-0000-0000-0000-ab000001234d \ No newline at end of file diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersByExternalId/DAEB0FCDD492D3F8A120619D33A96D09 b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersByExternalId/DAEB0FCDD492D3F8A120619D33A96D09 index b52600e..c338d3a 100644 --- a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersByExternalId/DAEB0FCDD492D3F8A120619D33A96D09 +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersByExternalId/DAEB0FCDD492D3F8A120619D33A96D09 @@ -1 +1 @@ -truefalseitpc://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444e-0000-0000-0000-ab71234c452d&type=mp3http://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444e-0000-0000-0000-ab71234c452d&type=mp3falsehttps://server.panopto.com/Panopto/Pages/Sessions/EmbeddedUpload.aspx?folderID=c9123444e-0000-0000-0000-ab71234c452dhttps://server.panopto.com/Panopto/Pages/EmbeddedList.aspx?embedded=1&folderID=c9123444e-0000-0000-0000-ab71234c452dtruec9123444e-0000-0000-0000-ab71234c452dfalsehttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?folderID=c9123444e-0000-0000-0000-ab71234c452dAutumnr 2015 - PSYCH 101 A Au 15: Introduction To Psychologyhttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?modalPage=FolderSettings&folderID=c9123444e-0000-0000-0000-ab71234c452ditpc://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444e-0000-0000-0000-ab71234c452d&type=mp4http://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444e-0000-0000-0000-ab71234c452d&type=mp4 +truefalseitpc://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444-0000-0000-0000-ab71234c452d&type=mp3http://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444-0000-0000-0000-ab71234c452d&type=mp3falsehttps://server.panopto.com/Panopto/Pages/Sessions/EmbeddedUpload.aspx?folderID=c9123444-0000-0000-0000-ab71234c452dhttps://server.panopto.com/Panopto/Pages/EmbeddedList.aspx?embedded=1&folderID=c9123444-0000-0000-0000-ab71234c452dtruec9123444-0000-0000-0000-ab71234c452dfalsehttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?folderID=c9123444-0000-0000-0000-ab71234c452dAutumnr 2015 - PSYCH 101 A Au 15: Introduction To Psychologyhttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?modalPage=FolderSettings&folderID=c9123444-0000-0000-0000-ab71234c452ditpc://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444-0000-0000-0000-ab71234c452d&type=mp4http://server.panopto.com/Panopto/Podcast/Podcast.ashx?courseid=c9123444-0000-0000-0000-ab71234c452d&type=mp4 diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersWithExternalContextByExternalId/6298A683FA88F4AC8518436715C5A45A b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersWithExternalContextByExternalId/6298A683FA88F4AC8518436715C5A45A new file mode 100644 index 0000000..5a6f032 --- /dev/null +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetAllFoldersWithExternalContextByExternalId/6298A683FA88F4AC8518436715C5A45A @@ -0,0 +1 @@ +truefalsefalsehttps://server.panopto.com/Panopto/Pages/Sessions/EmbeddedUpload.aspx?folderID=c9123444-0000-0000-0000-ab71234c452dhttps://server.panopto.com/Panopto/Pages/EmbeddedList.aspx?embedded=1&folderID=c9123444-0000-0000-0000-ab71234c452dtrue696c3acb-71c2-4071-9668-b18f00eecf3bfalsehttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?folderID=c9123444-0000-0000-0000-ab71234c452dAutumnr 2015 - PSYCH 101 A Au 15: Introduction To Psychologyhttps://server.panopto.com/Panopto/Pages/Sessions/List.aspx?modalPage=FolderSettings&folderID=c9123444-0000-0000-0000-ab71234c452dUWNetid-uw-test\\1730776 diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/0E33841B3F905C740C82794EC9920C48 b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/0E33841B3F905C740C82794EC9920C48 index 3a7ece3..d21f62d 100644 --- a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/0E33841B3F905C740C82794EC9920C48 +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/0E33841B3F905C740C82794EC9920C48 @@ -1 +1 @@ -b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-0880456dbb-8350-416c-a97d-36f683ce66dcAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file +b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-08c9123444-0000-0000-0000-ab71234c452dAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/4B8FDE6E65F308A114DF5C05EFE1BA31 b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/4B8FDE6E65F308A114DF5C05EFE1BA31 index 3a7ece3..d21f62d 100644 --- a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/4B8FDE6E65F308A114DF5C05EFE1BA31 +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsByExternalId/4B8FDE6E65F308A114DF5C05EFE1BA31 @@ -1 +1 @@ -b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-0880456dbb-8350-416c-a97d-36f683ce66dcAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file +b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-08c9123444-0000-0000-0000-ab71234c452dAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/8B4EF0CEB260E300112EDBF5EF4EE5A6 b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/8B4EF0CEB260E300112EDBF5EF4EE5A6 index 1e95825..3fec1ee 100644 --- a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/8B4EF0CEB260E300112EDBF5EF4EE5A6 +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/8B4EF0CEB260E300112EDBF5EF4EE5A6 @@ -1 +1 @@ -b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-0880456dbb-8350-416c-a97d-36f683ce66dcAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file +b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-08c9123444-0000-0000-0000-ab71234c452dAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file diff --git a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/EE5BF1A43C87AC958B88856CA5494F10 b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/EE5BF1A43C87AC958B88856CA5494F10 index 1e95825..3fec1ee 100644 --- a/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/EE5BF1A43C87AC958B88856CA5494F10 +++ b/scheduler/resources/panopto/file/BasicHttpBinding_ISessionManagement/GetSessionsById/EE5BF1A43C87AC958B88856CA5494F10 @@ -1 +1 @@ -b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-0880456dbb-8350-416c-a97d-36f683ce66dcAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file +b23e442b-abff-458e-b09b-d18851f617542100https://uw-test.hosted.panopto.com/Panopto/Pages/Editor/Default.aspx#673fcde2-4d70-4610-89b3-3638684cf90c2015-autumn-PSYCH-101-A-2015-12-08c9123444-0000-0000-0000-ab71234c452dAutumn 2015 - PSYCH 101 A: Introduction To Psychology673fcde2-4d70-4610-89b3-3638684cf90ctruefalsePSYCH 101 A - 2015-12-08https://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&notes=truehttps://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionOutputs53768edb-fa5f-4f36-9a06-253105354811https://uw-test.hosted.panopto.com/Panopto/Pages/Sessions/List.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c&modalPage=SessionShare2015-12-08T21:40:00ZScheduledScheduled recording/Panopto/Cache/4.9.2.22541/Images/no_thumbnail.pnghttps://uw-test.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=673fcde2-4d70-4610-89b3-3638684cf90c \ No newline at end of file diff --git a/scheduler/schedule.py b/scheduler/schedule.py index 1607f11..ef4265f 100644 --- a/scheduler/schedule.py +++ b/scheduler/schedule.py @@ -59,7 +59,7 @@ def course_recording_sessions(course, event): course = course.get_crosslisted_course() contact = course.course_event_title_and_contact() - folder = course.panopto_course_folder(contact['title_long']) + folder = course.panopto_course_folder() for rsv in event.reservations: if not rsv.is_instruction: @@ -82,8 +82,8 @@ def course_recording_sessions(course, event): session_external_ids.append(external_id) - event_session['schedulable'] = ( - folder['external_id'] and event_session['space']['id']) + event_session['schedulable'] = True if ( + folder['id'] and event_session['space']['id']) else False event_session['contact'] = contact @@ -236,7 +236,7 @@ def event_session_from_scheduled_recording(s): 'folder': { 'name': s.FolderName, 'id': s.FolderId, - 'external_id': s.FolderId, + 'external_id': None, }, 'is_broadcast': s.IsBroadcast # property below is added conditionally for events diff --git a/scheduler/test/api/test_session.py b/scheduler/test/api/test_session.py index e48f28c..a8486bc 100644 --- a/scheduler/test/api/test_session.py +++ b/scheduler/test/api/test_session.py @@ -37,7 +37,7 @@ def test_api_session(self): sessions['loginid'] = 'jfaculty' sessions['end_time'] = sessions['start_time'] sessions['recorder_id'] = '22e12346-1234-1234-4321-12347f1234c5' - sessions['folder_external_id'] = '2015-autumn-PSYCH-101-A' + sessions['folder_id'] = 'c9123444-0000-0000-0000-ab71234c452d' sessions['key'] = '9AC7325FB31465FF946FFFC5514E35CEB3F42C38' request = RequestFactory().post( url, sessions, content_type="application/json") diff --git a/scheduler/test/test_location_and_recordings.py b/scheduler/test/test_location_and_recordings.py index e8be3be..46ebb1c 100644 --- a/scheduler/test/test_location_and_recordings.py +++ b/scheduler/test/test_location_and_recordings.py @@ -13,7 +13,7 @@ course_test_override = override_settings( USER_MODULE='scheduler.org.uw.user', COURSES_MODULE='scheduler.org.uw.course', - RESERVATIONS_MODULE='scheduler.org.uw.reservations' + RESERVATIONS_MODULE='scheduler.org.uw.reservations', ) diff --git a/scheduler/utils/__init__.py b/scheduler/utils/__init__.py index d955154..a832035 100644 --- a/scheduler/utils/__init__.py +++ b/scheduler/utils/__init__.py @@ -27,3 +27,7 @@ def schedule_key(netid, name, external_id, recorder_id, start, end): getattr(settings, 'PANOPTO_API_TOKEN', '')) return sha1(to_sign.encode('utf-8')).hexdigest().upper() + + +def panopto_app_id(): + return getattr(settings, 'PANOPTO_API_APP_ID', None) diff --git a/scheduler/utils/recorder.py b/scheduler/utils/recorder.py index c5fef6e..47b00de 100644 --- a/scheduler/utils/recorder.py +++ b/scheduler/utils/recorder.py @@ -6,10 +6,6 @@ import re -class RecorderException(Exception): - pass - - def get_recorder_details(recorder_id): return get_api_recorder_details(RemoteRecorderManagement(), recorder_id) diff --git a/scheduler/utils/session.py b/scheduler/utils/session.py deleted file mode 100644 index a4cf407..0000000 --- a/scheduler/utils/session.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2024 UW-IT, University of Washington -# SPDX-License-Identifier: Apache-2.0 - -from panopto_client.session import SessionManagement - - -def get_sessions_by_external_ids(external_ids): - api = SessionManagement() - sessions = api.getSessionsByExternalId(external_ids) - return sessions.Session if (sessions and 'Session' in sessions and - len(sessions.Session)) else None - - -def get_sessions_by_session_ids(session_ids): - api = SessionManagement() - sessions = api.getSessionsById(session_ids) - return sessions.Session if (sessions and 'Session' in sessions and - len(sessions.Session)) else None diff --git a/scheduler/views/api/session.py b/scheduler/views/api/session.py index b9a21c3..352f4ec 100644 --- a/scheduler/views/api/session.py +++ b/scheduler/views/api/session.py @@ -3,15 +3,17 @@ from django.conf import settings from scheduler.views.rest_dispatch import RESTDispatch -from scheduler.exceptions import InvalidParamException, PanoptoUserException -from scheduler.utils import schedule_key +from scheduler.exceptions import ( + InvalidParamException, PanoptoUserException) +from scheduler.utils import schedule_key, panopto_app_id from scheduler.utils.validation import Validation from scheduler.panopto.folder import get_panopto_folder_creators from scheduler.dao.panopto.sessions import ( get_sessions_by_session_ids, update_session_external_id, update_session_is_broadcast, move_sessions, delete_sessions, - get_all_folders_by_external_id, get_folders_list, add_folder, - update_folder_external_id_with_provider) + get_all_folders_with_external_context_list, + get_all_folders_by_external_id, provision_external_course, + get_folders_list, add_folder) from scheduler.dao.panopto.access import ( get_session_access_details, update_session_is_public, grant_users_access_to_folder, revoke_users_access_from_folder) @@ -174,9 +176,9 @@ def put(self, request, *args, **kwargs): }) except InvalidParamException as ex: return self.error_response(400, "{}".format(ex)) - except Exception as ex: + except DataFailureException as ex: return self.error_response( - 500, "Unable to save session: {}".format(ex)) + 424, "Unable to save session: {}".format(ex)) def delete(self, request, *args, **kwargs): try: @@ -202,43 +204,8 @@ def delete(self, request, *args, **kwargs): return self.error_response( 400, "Invalid Parameter: {}".format(err)) - def _valid_folder(self, name, external_id): - try: - folder_id = Validation().panopto_id(external_id) - return folder_id - except InvalidParamException: - pass - - try: - if external_id and len(external_id): - folders = get_all_folders_by_external_id([external_id]) - if folders and len(folders) == 1 and len(folders[0]): - return folders[0][0].Id - - folders = get_folders_list(search_query=name) - if folders and len(folders): - for folder in folders: - if folder.Name == name: - folder_id = folder.Id - self._set_external_id(folder_id, external_id) - return folder_id - - new_folder = add_folder(name) - if not new_folder: - raise InvalidParamException( - 'Cannot add folder: {}'.format(name)) - - new_folder_id = new_folder.Id - self._set_external_id(new_folder_id, external_id) - return new_folder_id - except Exception as ex: - raise InvalidParamException('Cannot add folder: {}'.format(ex)) - - def _set_external_id(self, folder_id, external_id): - if external_id and len(external_id): - update_folder_external_id_with_provider( - folder_id, external_id, getattr( - settings, 'PANOPTO_API_APP_ID', '')) + def _valid_folder_id(self, folder_id): + return Validation().panopto_id(folder_id) def _validate_session(self, request_body): session = {} @@ -252,8 +219,8 @@ def _validate_session(self, request_body): data.get("external_id", "").strip()) session['recorder_id'] = self._valid_recorder_id( data.get("recorder_id", "").strip()) - session['folder_external_id'] = data.get( - "folder_external_id", "").strip() + session['folder_id'] = data.get( + "folder_id", "").strip() session['session_id'] = data.get("session_id", "").strip() if len(session['session_id']): @@ -268,8 +235,8 @@ def _validate_session(self, request_body): session['end_time'] = self._valid_time( data.get("end_time", "").strip()) session['folder_name'] = data.get("folder_name", "").strip() - session['folder_id'] = self._valid_folder( - session['folder_name'], session['folder_external_id']) + session['folder_id'] = self._valid_folder_id( + session['folder_id']) session['folder_creators'] = data.get("creators", None) # do not permit param tamperings diff --git a/setup.py b/setup.py index 20718d5..536265f 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,8 @@ 'django-compressor', 'django-blti~=2.2', 'django-userservice~=3.2', + 'lxml<5', + 'xmlsec==1.3.13', 'uw-memcached-clients~=1.0', 'UW-RestClients-Core~=1.4', 'UW-RestClients-SWS~=2.4',