def login(self): """Initializes an authentication, provided we have the credentials for it. :returns: The session. This is useful for jQuery-like command chaining:: s = webuntis.Session(...).login() :raises: :py:class:`webuntis.errors.BadCredentialsError` -- Username/Password missing or invalid. :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a session ID for unknown reasons. """ try: username = self.config["username"] password = self.config["password"] useragent = self.config["useragent"] except KeyError as e: raise errors.BadCredentialsError("Missing config: " + str(e)) res = self._request( "authenticate", {"user": username, "password": password, "client": useragent}, use_login_repeat=False ) if "sessionId" in res: sid = self.config["jsessionid"] = res["sessionId"] log("debug", "Did get a jsessionid from the server: " + sid) else: raise errors.AuthError("Something went wrong while authenticating", res) return self
def _request(self, method, params=None, use_login_repeat=None): if not isinstance(method, unicode_string): method = method.decode('ascii') if use_login_repeat is None: use_login_repeat = (method not in ('logout', 'authenticate')) attempts_left = self.config['login_repeat'] if use_login_repeat else 0 data = None while data is None: try: data = rpc_request(self.config, method, params or {}) except errors.NotLoggedInError: if attempts_left > 0: self.logout(suppress_errors=True) self.login() else: raise errors.NotLoggedInError( 'Tried to login several times, failed. Original method' ' was ' + method) else: log('debug', "RETURN:" + str(data)) return data attempts_left -= 1 # new round!
def _request(self, method, params=None, use_login_repeat=None): if not isinstance(method, unicode_string): method = method.decode("ascii") if use_login_repeat is None: use_login_repeat = method not in ("logout", "authenticate") attempts_left = self.config["login_repeat"] if use_login_repeat else 0 data = None while data is None: try: data = rpc_request(self.config, method, params or {}) except errors.NotLoggedInError: if attempts_left > 0: self.logout(suppress_errors=True) self.login() else: raise errors.NotLoggedInError( "Tried to login several times, failed. Original method" " was " + method ) else: log("debug", "RETURN:" + str(data)) return data attempts_left -= 1 # new round!
def _parse_error_code(request_body, result_body): '''A helper function for handling JSON error codes.''' log('error', result_body) try: error = result_body['error'] exc = _errorcodes[error['code']](error['message']) except KeyError: exc = errors.RemoteError( ('Some JSON-RPC-ish error happened. Please report this to the ' 'developer so he can implement a proper handling.'), str(result_body), str(request_body) ) raise exc
def _parse_error_code(request_body, result_body): """A helper function for handling JSON error codes.""" log("error", result_body) try: error = result_body[u"error"] code, message = error[u"code"], error[u"message"] except KeyError: code = None # None doesn't exist in_errorcodes message = "Some error happened and there is no information provided " "what went wrong." exc = _errorcodes.get(code, errors.RemoteError)(message) exc.request = request_body exc.result = result_body exc.code = code raise exc
def _parse_error_code(request_body, result_body): """A helper function for handling JSON error codes.""" log('error', result_body) try: error = result_body[u'error'] code, message = error[u'code'], error[u'message'] except KeyError: code = None # None doesn't exist in_errorcodes message = ('Some error happened and there is no information provided ' 'what went wrong.') exc = _errorcodes.get(code, errors.RemoteError)(message) exc.request = request_body exc.result = result_body exc.code = code raise exc
def _send_request(url, data, headers): '''Sends a POST request given the endpoint URL, JSON-encodable data and a dictionary with headers. ''' request = urlrequest.Request(url, json.dumps(data).encode(), headers) # this will eventually raise errors, e.g. if there's an unexpected http # status code result_obj = urlrequest.urlopen(request) result = result_obj.read().decode('utf-8') try: result_data = json.loads(result) log('debug', 'Valid JSON found') except ValueError: raise errors.RemoteError('Invalid JSON', str(result)) else: return result_data
def _send_request(url, data, headers, http_session=None): """Sends a POST request given the endpoint URL, JSON-encodable data, a dictionary with headers and, optionally, a session object for requests. """ if http_session is None: http_session = requests.session() r = http_session.post(url, data=json.dumps(data), headers=headers) result = r.text # this will eventually raise errors, e.g. on timeout try: result_data = json.loads(result) log("debug", "Valid JSON found") except ValueError: raise errors.RemoteError("Invalid JSON", result) else: return result_data
def _send_request(url, data, headers, http_session=None): """Sends a POST request given the endpoint URL, JSON-encodable data, a dictionary with headers and, optionally, a session object for requests. """ if http_session is None: http_session = requests.session() r = http_session.post(url, data=json.dumps(data), headers=headers) result = r.text # this will eventually raise errors, e.g. on timeout try: result_data = json.loads(result) log('debug', 'Valid JSON found') except ValueError: raise errors.RemoteError('Invalid JSON', result) else: return result_data
def login(self): '''Initializes an authentication, provided we have the credentials for it. :returns: The session. This is useful for jQuery-like command chaining:: s = webuntis.Session(...).login() :raises: :py:class:`webuntis.errors.BadCredentialsError` -- Username/Password missing or invalid. :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a session ID for unknown reasons. ''' if 'username' not in self.config \ or 'password' not in self.config: raise errors.BadCredentialsError('No login data specified.') log('debug', 'Trying to authenticate with username/password...') log('debug', 'Username: %s Password: %s' % (self.config['username'], self.config['password'])) res = self._request('authenticate', { 'user': self.config['username'], 'password': self.config['password'], 'client': self.config['useragent'] }, use_login_repeat=False) log('debug', res) if 'sessionId' in res: log('debug', 'Did get a jsessionid from the server:') self.config['jsessionid'] = res['sessionId'] log('debug', self.config['jsessionid']) else: raise errors.AuthError( 'Something went wrong while authenticating', res ) return self
def rpc_request(config, method, params): ''' A method for sending a JSON-RPC request. :param config: A dictionary containing ``useragent``, ``server``, ``school``, ``username`` and ``password`` :type config: dict :param method: The JSON-RPC method to be executed :type method: str :param params: JSON-RPC parameters to the method (should be JSON serializable) :type params: dict ''' server = config['server'] school = config['school'] useragent = config['useragent'] assert isinstance(method, unicode_string) assert isinstance(server, unicode_string) assert isinstance(school, unicode_string) assert isinstance(useragent, unicode_string) for v in params.values(): assert not isinstance(v, bytestring) url = server + u'?school=' + school headers = {u'User-Agent': useragent, u'Content-Type': u'application/json'} request_body = { u'id': str(datetime.datetime.today()), u'method': method, u'params': params, u'jsonrpc': u'2.0' } if method != u'authenticate': if 'jsessionid' in config: assert isinstance(config['jsessionid'], unicode_string) headers['Cookie'] = u'JSESSIONID=' + config['jsessionid'] else: raise errors.NotLoggedInError( 'Don\'t have JSESSIONID. Did you already log out?') log('debug', 'Making new request:') log('debug', 'URL: ' + url) if method != u'authenticate': # user credentials will not be logged - fixing #14 log('debug', 'DATA: ' + str(request_body)) if '_http_session' not in config: config['_http_session'] = requests.session() http_session = config['_http_session'] result_body = _send_request(url, request_body, headers, http_session) return _parse_result(request_body, result_body)
def login(self): """Initializes an authentication, provided we have the credentials for it. :returns: The session. This is useful for jQuery-like command chaining:: s = webuntis.Session(...).login() :raises: :py:class:`webuntis.errors.BadCredentialsError` -- Username/Password missing or invalid. :raises: :py:class:`webuntis.errors.AuthError` -- Didn't receive a session ID for unknown reasons. """ try: username = self.config['username'] password = self.config['password'] useragent = self.config['useragent'] except KeyError as e: raise errors.BadCredentialsError('Missing config: ' + str(e)) res = self._request('authenticate', { 'user': username, 'password': password, 'client': useragent }, use_login_repeat=False) if 'sessionId' in res: sid = self.config['jsessionid'] = res['sessionId'] log('debug', 'Did get a jsessionid from the server: ' + sid) else: raise errors.AuthError('Something went wrong while authenticating', res) return self
def login(self): '''Initializes an authentication, provided we have the credentials for it. :returns: The session. This is useful for jQuery-like command chaining:: s = webuntis.Session(...).login() :raises: :py:class:`webuntis.errors.BadCredentialsError` -- Username/Password missing or invalid. :raises: :py:class:`webuntis.errors.AuthError` -- Didn't recieve a session ID for unknown reasons. ''' try: username = self.config['username'] password = self.config['password'] useragent = self.config['useragent'] except KeyError as e: raise errors.BadCredentialsError('Missing config: ' + str(e)) res = self._request('authenticate', { 'user': username, 'password': password, 'client': useragent }, use_login_repeat=False) if 'sessionId' in res: sid = self.config['jsessionid'] = res['sessionId'] log('debug', 'Did get a jsessionid from the server: ' + sid) else: raise errors.AuthError('Something went wrong while authenticating', res) return self
def rpc_request(config, method, params): ''' A method for sending a JSON-RPC request. :param config: A dictionary containing ``useragent``, ``server``, ``school``, ``username`` and ``password`` :type config: dict :param method: The JSON-RPC method to be executed :type method: str :param params: JSON-RPC parameters to the method (should be JSON serializable) :type params: dict ''' url = config['server'] + \ '?school=' + \ config['school'] headers = { 'User-Agent': config['useragent'], 'Content-Type': 'application/json' } request_body = { 'id': str(datetime.datetime.today()), 'method': method, 'params': params, 'jsonrpc': '2.0' } if method != 'authenticate': if 'jsessionid' not in config: raise errors.NotLoggedInError( 'Don\'t have JSESSIONID. Did you already log out?') else: headers['Cookie'] = 'JSESSIONID=' + \ config['jsessionid'] log('debug', 'Making new request:') log('debug', 'URL: ' + url) log('debug', 'DATA: ' + str(request_body)) result_body = _send_request( url, request_body, headers ) return _parse_result(request_body, result_body)
def rpc_request(config, method, params): """ A method for sending a JSON-RPC request. :param config: A dictionary containing ``useragent``, ``server``, ``school``, ``username`` and ``password`` :type config: dict :param method: The JSON-RPC method to be executed :type method: str :param params: JSON-RPC parameters to the method (should be JSON serializable) :type params: dict """ server = config["server"] school = config["school"] useragent = config["useragent"] assert isinstance(method, unicode_string) assert isinstance(server, unicode_string) assert isinstance(school, unicode_string) assert isinstance(useragent, unicode_string) for v in params.values(): assert not isinstance(v, bytestring) url = server + u"?school=" + school headers = {u"User-Agent": useragent, u"Content-Type": u"application/json"} request_body = {u"id": str(datetime.datetime.today()), u"method": method, u"params": params, u"jsonrpc": u"2.0"} if method != u"authenticate": if "jsessionid" in config: assert isinstance(config["jsessionid"], unicode_string) headers["Cookie"] = u"JSESSIONID=" + config["jsessionid"] else: raise errors.NotLoggedInError("Don't have JSESSIONID. Did you already log out?") log("debug", "Making new request:") log("debug", "URL: " + url) log("debug", "DATA: " + str(request_body)) if "_http_session" not in config: config["_http_session"] = requests.session() http_session = config["_http_session"] result_body = _send_request(url, request_body, headers, http_session) return _parse_result(request_body, result_body)
def rpc_request(config, method, params): """ A method for sending a JSON-RPC request. :param config: A dictionary containing ``useragent``, ``server``, ``school``, ``username`` and ``password`` :type config: dict or FilterDict :param method: The JSON-RPC method to be executed :type method: str :param params: JSON-RPC parameters to the method (should be JSON serializable) :type params: dict """ server = config['server'] school = config['school'] useragent = config['useragent'] assert isinstance(method, unicode_string) assert isinstance(server, unicode_string) assert isinstance(school, unicode_string) assert isinstance(useragent, unicode_string) for v in params.values(): assert not isinstance(v, bytestring) url = server + u'?school=' + school headers = { u'User-Agent': useragent, u'Content-Type': u'application/json' } request_body = { u'id': _request_getid(), u'method': method, u'params': params, u'jsonrpc': u'2.0' } if method != u'authenticate': if 'jsessionid' in config: assert isinstance(config['jsessionid'], unicode_string) headers['Cookie'] = u'JSESSIONID=' + config['jsessionid'] else: raise errors.NotLoggedInError( 'Don\'t have JSESSIONID. Did you already log out?') log('debug', 'Making new request:') log('debug', 'URL: ' + url) if method != u'authenticate': # user credentials will not be logged - fixing #14 log('debug', 'DATA: ' + str(request_body)) if '_http_session' not in config: config['_http_session'] = requests.session() http_session = config['_http_session'] result_body = _send_request( url, request_body, headers, http_session ) return _parse_result(request_body, result_body)