lms.backend.instance
1import typing 2 3import edq.net.request 4import requests 5 6import lms.backend.blackboard.backend 7import lms.backend.canvas.backend 8import lms.backend.moodle.backend 9import lms.model.constants 10import lms.model.backend 11 12def get_backend( 13 server: typing.Union[str, None] = None, 14 backend_type: typing.Union[str, None] = None, 15 **kwargs: typing.Any) -> lms.model.backend.APIBackend: 16 """ 17 Get an instance of an API backend from the given information. 18 If the backend type is not explicitly provided, 19 this function will attempt to guess it from other information. 20 """ 21 22 if (server is None): 23 raise ValueError("No LMS server address provided.") 24 25 server = server.strip() 26 if (not server.startswith('http')): 27 server = 'http://' + server 28 29 backend_type = guess_backend_type(server, backend_type = backend_type) 30 if (backend_type is None): 31 raise ValueError(f"Unable to guess backend type from server: '{server}'.") 32 33 if (backend_type == lms.model.constants.BACKEND_TYPE_CANVAS): 34 return lms.backend.canvas.backend.CanvasBackend(server, **kwargs) 35 36 if (backend_type == lms.model.constants.BACKEND_TYPE_MOODLE): 37 return lms.backend.moodle.backend.MoodleBackend(server, **kwargs) 38 39 if (backend_type == lms.model.constants.BACKEND_TYPE_BLACKBOARD): 40 return lms.backend.blackboard.backend.BlackboardBackend(server, **kwargs) 41 42 if (backend_type in lms.model.constants.BACKEND_TYPES): 43 raise ValueError(f"Instance creation not yet supported for backend type: '{backend_type}'.") 44 45 raise ValueError(f"Unknown backend type: '{backend_type}'. Known backend types: {lms.model.constants.BACKEND_TYPES}.") 46 47def guess_backend_type( 48 server: typing.Union[str, None] = None, 49 backend_type: typing.Union[str, None] = None, 50 **kwargs: typing.Any) -> typing.Union[str, None]: 51 """ 52 Attempt to guess the backend type from a server. 53 This function will return None it cannot guess the backend type. 54 """ 55 56 if (backend_type is not None): 57 return backend_type 58 59 if (server is None): 60 return None 61 62 # Try looking at the URL string itself. 63 backend_type = guess_backend_type_from_url(server) 64 if (backend_type is not None): 65 return backend_type 66 67 # Make a request to the server and examine the response. 68 backend_type = guess_backend_type_from_request(server) 69 if (backend_type is not None): 70 return backend_type 71 72 return None 73 74def guess_backend_type_from_request(server: str, timeout_secs: float = edq.net.request.DEFAULT_REQUEST_TIMEOUT_SECS) -> typing.Union[str, None]: 75 """ 76 Attempt to guess the backend type by pinging the server. 77 This function will not do any lexical analysis on the server string. 78 """ 79 80 options = { 81 'allow_redirects': False, 82 } 83 84 try: 85 response, _ = edq.net.request.make_get(server, 86 raise_for_status = False, 87 timeout_secs = timeout_secs, 88 additional_requests_options = options) 89 except requests.exceptions.ConnectionError: 90 return None 91 except requests.exceptions.Timeout: 92 return None 93 94 header_keys = [key.lower() for key in response.headers.keys()] 95 96 # Blackboard sends a special header. 97 if ('x-blackboard-product' in header_keys): 98 return lms.model.constants.BACKEND_TYPE_BLACKBOARD 99 100 # Canvas sends a special header. 101 if ('x-canvas-meta' in header_keys): 102 return lms.model.constants.BACKEND_TYPE_CANVAS 103 104 # Canvas requests that a specific cookie is set. 105 if ('_normandy_session' in response.headers.get('set-cookie', '')): 106 return lms.model.constants.BACKEND_TYPE_CANVAS 107 108 # Moodle will try to redirect with a special header. 109 if (response.headers.get('x-redirect-by', '').lower() == 'moodle'): 110 return lms.model.constants.BACKEND_TYPE_MOODLE 111 112 # Moodle requests that a specific cookie is set. 113 if ('MoodleSession' in response.headers.get('set-cookie', '')): 114 return lms.model.constants.BACKEND_TYPE_MOODLE 115 116 return None 117 118def guess_backend_type_from_url(server: str) -> typing.Union[str, None]: 119 """ 120 Attempt to guess the backend type only from a string server URL. 121 This function will only do lexical analysis on the string (no HTTP requests will be made). 122 """ 123 124 server = server.lower().strip() 125 126 if ('canvas' in server): 127 return lms.model.constants.BACKEND_TYPE_CANVAS 128 129 if ('moodle' in server): 130 return lms.model.constants.BACKEND_TYPE_MOODLE 131 132 if ('blackboard' in server): 133 return lms.model.constants.BACKEND_TYPE_BLACKBOARD 134 135 return None
def
get_backend( server: Optional[str] = None, backend_type: Optional[str] = None, **kwargs: Any) -> lms.model.backend.APIBackend:
13def get_backend( 14 server: typing.Union[str, None] = None, 15 backend_type: typing.Union[str, None] = None, 16 **kwargs: typing.Any) -> lms.model.backend.APIBackend: 17 """ 18 Get an instance of an API backend from the given information. 19 If the backend type is not explicitly provided, 20 this function will attempt to guess it from other information. 21 """ 22 23 if (server is None): 24 raise ValueError("No LMS server address provided.") 25 26 server = server.strip() 27 if (not server.startswith('http')): 28 server = 'http://' + server 29 30 backend_type = guess_backend_type(server, backend_type = backend_type) 31 if (backend_type is None): 32 raise ValueError(f"Unable to guess backend type from server: '{server}'.") 33 34 if (backend_type == lms.model.constants.BACKEND_TYPE_CANVAS): 35 return lms.backend.canvas.backend.CanvasBackend(server, **kwargs) 36 37 if (backend_type == lms.model.constants.BACKEND_TYPE_MOODLE): 38 return lms.backend.moodle.backend.MoodleBackend(server, **kwargs) 39 40 if (backend_type == lms.model.constants.BACKEND_TYPE_BLACKBOARD): 41 return lms.backend.blackboard.backend.BlackboardBackend(server, **kwargs) 42 43 if (backend_type in lms.model.constants.BACKEND_TYPES): 44 raise ValueError(f"Instance creation not yet supported for backend type: '{backend_type}'.") 45 46 raise ValueError(f"Unknown backend type: '{backend_type}'. Known backend types: {lms.model.constants.BACKEND_TYPES}.")
Get an instance of an API backend from the given information. If the backend type is not explicitly provided, this function will attempt to guess it from other information.
def
guess_backend_type( server: Optional[str] = None, backend_type: Optional[str] = None, **kwargs: Any) -> Optional[str]:
48def guess_backend_type( 49 server: typing.Union[str, None] = None, 50 backend_type: typing.Union[str, None] = None, 51 **kwargs: typing.Any) -> typing.Union[str, None]: 52 """ 53 Attempt to guess the backend type from a server. 54 This function will return None it cannot guess the backend type. 55 """ 56 57 if (backend_type is not None): 58 return backend_type 59 60 if (server is None): 61 return None 62 63 # Try looking at the URL string itself. 64 backend_type = guess_backend_type_from_url(server) 65 if (backend_type is not None): 66 return backend_type 67 68 # Make a request to the server and examine the response. 69 backend_type = guess_backend_type_from_request(server) 70 if (backend_type is not None): 71 return backend_type 72 73 return None
Attempt to guess the backend type from a server. This function will return None it cannot guess the backend type.
def
guess_backend_type_from_request(server: str, timeout_secs: float = 10.0) -> Optional[str]:
75def guess_backend_type_from_request(server: str, timeout_secs: float = edq.net.request.DEFAULT_REQUEST_TIMEOUT_SECS) -> typing.Union[str, None]: 76 """ 77 Attempt to guess the backend type by pinging the server. 78 This function will not do any lexical analysis on the server string. 79 """ 80 81 options = { 82 'allow_redirects': False, 83 } 84 85 try: 86 response, _ = edq.net.request.make_get(server, 87 raise_for_status = False, 88 timeout_secs = timeout_secs, 89 additional_requests_options = options) 90 except requests.exceptions.ConnectionError: 91 return None 92 except requests.exceptions.Timeout: 93 return None 94 95 header_keys = [key.lower() for key in response.headers.keys()] 96 97 # Blackboard sends a special header. 98 if ('x-blackboard-product' in header_keys): 99 return lms.model.constants.BACKEND_TYPE_BLACKBOARD 100 101 # Canvas sends a special header. 102 if ('x-canvas-meta' in header_keys): 103 return lms.model.constants.BACKEND_TYPE_CANVAS 104 105 # Canvas requests that a specific cookie is set. 106 if ('_normandy_session' in response.headers.get('set-cookie', '')): 107 return lms.model.constants.BACKEND_TYPE_CANVAS 108 109 # Moodle will try to redirect with a special header. 110 if (response.headers.get('x-redirect-by', '').lower() == 'moodle'): 111 return lms.model.constants.BACKEND_TYPE_MOODLE 112 113 # Moodle requests that a specific cookie is set. 114 if ('MoodleSession' in response.headers.get('set-cookie', '')): 115 return lms.model.constants.BACKEND_TYPE_MOODLE 116 117 return None
Attempt to guess the backend type by pinging the server. This function will not do any lexical analysis on the server string.
def
guess_backend_type_from_url(server: str) -> Optional[str]:
119def guess_backend_type_from_url(server: str) -> typing.Union[str, None]: 120 """ 121 Attempt to guess the backend type only from a string server URL. 122 This function will only do lexical analysis on the string (no HTTP requests will be made). 123 """ 124 125 server = server.lower().strip() 126 127 if ('canvas' in server): 128 return lms.model.constants.BACKEND_TYPE_CANVAS 129 130 if ('moodle' in server): 131 return lms.model.constants.BACKEND_TYPE_MOODLE 132 133 if ('blackboard' in server): 134 return lms.model.constants.BACKEND_TYPE_BLACKBOARD 135 136 return None
Attempt to guess the backend type only from a string server URL. This function will only do lexical analysis on the string (no HTTP requests will be made).