diff options
author | Aleš Smodiš <aless@guru.si> | 2015-10-08 18:56:48 +0200 |
---|---|---|
committer | Aleš Smodiš <aless@guru.si> | 2015-10-08 18:56:48 +0200 |
commit | 76bfb287b51bd97c9ca0bfc4e7760b7ee8e15b47 (patch) | |
tree | 1124ec688054e2adb31f8a12c84115ec55381d7a /server/handlers.py | |
parent | b6eeda1a66da16f90d02dd5d439d5cc5088c1a88 (diff) |
Reworked session handling.
* All requests have a session ID, except for the initial create_session system messages.
* User session can be in an authenticated or anonymous state.
* In anonymous state it is not possible to perform user actions.
* Logout has been implemented.
* Sessions timeout and are cleared after a period of inactivity (1 hour).
* Bugfixed the lang setting handling.
* Renamed get_problem -> get_current_solution, return only the user's current solution, not the whole problem data.
Diffstat (limited to 'server/handlers.py')
-rw-r--r-- | server/handlers.py | 78 |
1 files changed, 41 insertions, 37 deletions
diff --git a/server/handlers.py b/server/handlers.py index a1bfbd7..1ab09f3 100644 --- a/server/handlers.py +++ b/server/handlers.py @@ -16,25 +16,20 @@ class CodeqService(object): pass -class ProblemList(CodeqService): - """List all available problems to the client. +class CreateSession(CodeqService): + """Creates a new anonymous session. + To promote the session to the authenticated status, a subsequent + login or signup must follow. """ session_is_optional = True def process(self, request): - js = request.data - language = js.get('language') - if language is None: - request.reply({'code': 1, 'message': 'Language was not provided'}) - else: - request.reply({'code': 0, 'message': 'ok', 'problems': server.problems.list_problems(language)}) + request.reply({'code': 0, 'message': 'OK', 'sid': server.user_session.UserSession().get_sid()}) class Login(CodeqService): - """Logs in a client, creating a new session. + """Logs in a client, authenticating the session. """ - session_is_optional = True - def process(self, request): js = request.data username = js.get('username') @@ -44,35 +39,39 @@ class Login(CodeqService): elif password is None: request.reply({'code': 2, 'message': 'Password was not provided'}) else: + session = request.session try: - session = server.user_session.authenticate_and_create_session(username, password) + session.login(username, password) except AuthenticationFailed: request.reply({'code': 3, 'message': 'Username or password do not match'}) else: - if request.session: - request.session.destroy() settings = session.get_settings() - request.reply({'code': 0, 'message': 'OK', 'sid':session.get_sid(), 'settings':settings}) + request.reply({'code': 0, 'message': 'OK', 'settings': settings}) -class Signup(CodeqService): - session_is_optional = True +class Logout(CodeqService): + def process(self, request): + request.session.destroy() + request.reply({'code': 0, 'message': 'OK'}) + +class Signup(CodeqService): def process(self, request): js = request.data username = js.get('username') password = js.get('password') + lang = js.get('lang') or 'en' if username is None: request.reply({'code': 1, 'message': 'Username was not provided'}) elif password is None: request.reply({'code': 2, 'message': 'Password was not provided'}) else: try: - server.user_session.signup(username, password) + request.session.signup(username, password, lang) except UserExists: request.reply({'code': 3, 'message': 'Username already exists'}) except SignupFailed: - request.reply({'code': 4, 'message': 'Signn up failed'}) + request.reply({'code': 4, 'message': 'Sign-up failed'}) else: request.reply({'code': 0, 'message': 'OK'}) @@ -92,7 +91,7 @@ class ChangePassword(CodeqService): request.reply({'code': 0, 'message': 'OK'}) -class Settings(CodeqService): +class UpdateSettings(CodeqService): def process(self, request): js = request.data settings = js.get('settings') @@ -101,7 +100,6 @@ class Settings(CodeqService): else: try: request.session.update_settings(settings) - request.session.write_settings_to_db() except NoSuchSession: request.reply({'code': 2, 'message': 'No such session'}) else: @@ -246,20 +244,15 @@ class Test(CodeqService): request.reply({'code': 0, 'message': 'ok', 'hints': hints}) -class GetProblem(CodeqService): +class GetCurrentSolution(CodeqService): def process(self, request): js = request.data - language = js.get('language') - problem_group = js.get('problem_group') - problem = js.get('problem') - if language is None: - request.reply({'code': 1, 'message': 'Language identifier not given'}) - elif problem_group is None: - request.reply({'code': 2, 'message': 'Problem group identifier not given'}) - elif problem is None: - request.reply({'code': 3, 'message': 'Problem identifier not given'}) + problem_id = js.get('problem_id') + if problem_id is None: + request.reply({'code': 1, 'message': 'Problem ID not specified'}) else: - request.reply({'code': 0, 'message': 'ok', 'data': request.session.get_problem_data(language, problem_group, problem)}) + request.reply({'code': 0, 'message': 'ok', 'data': request.session.current_solution(problem_id)}) + class LoadProblem(CodeqService): def process(self, request): @@ -273,26 +266,28 @@ class LoadProblem(CodeqService): else: request.reply({'code': 0, 'message': 'OK'}) + class EndProblem(CodeqService): def process(self, request): request.session.end_language_session() request.end() + # maps actions to their handlers incoming_handlers = { - 'list_problems': ProblemList(), + 'create_session': CreateSession(), 'login': Login(), 'signup': Signup(), 'change_password': ChangePassword(), - 'get_problem': GetProblem(), - 'logout': None, + 'get_current_solution': GetCurrentSolution(), + 'logout': Logout(), 'activity': Activity(), 'query': Query(), 'python_exec': PythonExec(), 'python_push': PythonPush(), 'python_stop': PythonStop(), 'hint': Hint(), - 'settings': Settings(), + 'update_settings': UpdateSettings(), 'test': Test(), 'load_problem': LoadProblem(), 'end_problem': EndProblem() @@ -323,6 +318,7 @@ class Request(object): """ if data is None: self.end() + return if self._original_sid is not None: sid = data.get('sid') if sid is None: @@ -356,10 +352,18 @@ def _invoke_handler(handler, request): logging.error('ERROR: the request was not concluded!') request.reply({'code': -1, 'message': 'Request processing did not provide a reply'}) logging.debug('Processing finished') + except NotLoggedIn: + if request.is_finished: + logging.error('Caught the NotLoggedIn exception, but the request has already been replied to!') + else: + request.reply({'code': -1, 'message': 'Cannot execute the request: not logged in'}) except Exception as e: logging.critical('ERROR: data processing failed: ' + str(e)) logging.critical(traceback.format_exc()) - request.reply({'code': -1, 'message': 'Internal error: ' + str(e)}) + if request.is_finished: + logging.critical('The request has already been replied to, the client will not be aware of the error!') + else: + request.reply({'code': -1, 'message': 'Internal error: ' + str(e)}) def serve_request(json_obj): if not isinstance(json_obj, dict): |