From be830a9e9feab28d52e8d830723e44eae1ecb27a Mon Sep 17 00:00:00 2001 From: ClysmiC Date: Fri, 12 Feb 2016 16:04:17 -0500 Subject: [PATCH 1/2] Implements logout and separate navbar for logged in/out users -closes issue #37 -closes issue #39 --- classrank/handlers/__init__.py | 8 ++++++-- classrank/handlers/auth.py | 12 ++++++++++++ classrank/routing.py | 1 + classrank/templates/navbar.html | 7 +------ config.json.example | 3 ++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/classrank/handlers/__init__.py b/classrank/handlers/__init__.py index 55b8866..7873fa2 100644 --- a/classrank/handlers/__init__.py +++ b/classrank/handlers/__init__.py @@ -5,13 +5,17 @@ class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.db = self.application.db - self.pages = self.application.settings['pages'] def render(self, template_name, **kwargs): """ binds certain global settings so that they are always passed into the template """ - kwargs['pages'] = self.pages + if(self.get_current_user()): + pages = self.application.settings['logged_in_pages'] + else: + pages = self.application.settings['logged_out_pages'] + + kwargs['pages'] = pages return super(BaseHandler, self).render(template_name, **kwargs) def get_current_user(self): diff --git a/classrank/handlers/auth.py b/classrank/handlers/auth.py index 540cb2d..c623134 100644 --- a/classrank/handlers/auth.py +++ b/classrank/handlers/auth.py @@ -1,4 +1,5 @@ import tornado.escape +from tornado.web import authenticated from classrank.database.wrapper import Query, NoResultFound, IntegrityError from . import BaseHandler @@ -59,3 +60,14 @@ def authorize(self, user): self.set_secure_cookie("user", tornado.escape.json_encode(user)) else: self.clear_cookie("user") + +class LogoutHandler(BaseHandler): + @authenticated + def get(self): + self.clear_cookie("user") + self.redirect("/") + + @authenticated + def post(self): + self.clear_cookie("user") + self.redirect("/") diff --git a/classrank/routing.py b/classrank/routing.py index 037e99a..ebda4b7 100644 --- a/classrank/routing.py +++ b/classrank/routing.py @@ -5,6 +5,7 @@ routes = [ (r'/', splash.SplashHandler), (r'/login/?', auth.LoginHandler), + (r'/logout/?', auth.LogoutHandler), (r'/register/?', auth.RegistrationHandler), (r'/welcome/?', welcome.WelcomeHandler), ] \ No newline at end of file diff --git a/classrank/templates/navbar.html b/classrank/templates/navbar.html index 0fc2ac4..cabb625 100644 --- a/classrank/templates/navbar.html +++ b/classrank/templates/navbar.html @@ -2,12 +2,7 @@ ClassRank diff --git a/config.json.example b/config.json.example index 13f1ccf..211bfff 100644 --- a/config.json.example +++ b/config.json.example @@ -1,6 +1,7 @@ { "autoreload": true, "cookie_secret": "This is actually a secret cookie!986425&(!@", - "pages": ["Dashboard", "Search", "Rate", "Privacy", "Settings"], + "logged_in_pages": ["dashboard", "search", "rate", "privacy", "settings", "logout"], + "logged_out_pages": ["login", "register"], "login_url": "/login" } \ No newline at end of file From e64d68e57feca306efcebf8a8483f5a2562e499f Mon Sep 17 00:00:00 2001 From: ClysmiC Date: Fri, 12 Feb 2016 16:46:37 -0500 Subject: [PATCH 2/2] Added test for logout --- classrank/handlers/auth.py | 4 ++-- test/test_application.py | 36 ++++++++++++++++++++++++++---------- test/test_handlers.py | 12 ++++++------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/classrank/handlers/auth.py b/classrank/handlers/auth.py index c623134..e1dfc34 100644 --- a/classrank/handlers/auth.py +++ b/classrank/handlers/auth.py @@ -65,9 +65,9 @@ class LogoutHandler(BaseHandler): @authenticated def get(self): self.clear_cookie("user") - self.redirect("/") + return self.redirect("/") @authenticated def post(self): self.clear_cookie("user") - self.redirect("/") + return self.redirect("/") diff --git a/test/test_application.py b/test/test_application.py index 26357ce..de1dabf 100644 --- a/test/test_application.py +++ b/test/test_application.py @@ -17,7 +17,8 @@ def get_app(self): "static_path": os.path.join(os.path.dirname(__file__), "../classrank/static"), "template_path": os.path.join(os.path.dirname(__file__), "../classrank/templates"), - "pages": ["Page", "Other Page"], + "logged_in_pages": ["dashboard", "search", "rate", "privacy", "settings", "logout"], + "logged_out_pages": ["login", "register"], "cookie_secret": test_cookie_secret, "login_url": "/login" } @@ -75,19 +76,21 @@ def create_example_user(self): return body def test_login_post_success(self): - body = self.create_example_user() - - with patch('classrank.handlers._authenticate.hash_pw') as hash_pass: - with patch( - 'classrank.handlers.BaseHandler.get_current_user') as authenticator: - authenticator.return_value = "tester" - hash_pass.return_value = "secret" - - response = self.fetch("/login", method="POST", body=body) + hash_pass, response = self.login() self.assertEqual(b"You're allowed here!", response.body) self.assertEqual(("password", "salt"), hash_pass.call_args[0]) + def test_logout(self): + self.login() + + with patch('classrank.handlers.BaseHandler.get_current_user') as auth: + auth.return_value = "tester" + response = self.fetch("/logout", method="GET") + + self.assertIn("ClassRank".encode('utf-8'), response.body) + + def test_register_existing_user(self): self.create_example_user() body = urllib.parse.urlencode({"email": "test@test.com", "school": "test", @@ -96,3 +99,16 @@ def test_register_existing_user(self): response = self.fetch("/register", method="POST", body=body) self.assertEqual(self.fetch('/register').body, response.body) + + def login(self): + body = self.create_example_user() + + with patch('classrank.handlers._authenticate.hash_pw') as hash_pass: + with patch( + 'classrank.handlers.BaseHandler.get_current_user') as authenticator: + authenticator.return_value = "tester" + hash_pass.return_value = "secret" + + return hash_pass, self.fetch("/login", method="POST", body=body) + + diff --git a/test/test_handlers.py b/test/test_handlers.py index ef958e7..d07d2c9 100644 --- a/test/test_handlers.py +++ b/test/test_handlers.py @@ -11,16 +11,16 @@ class TestBaseHandler(unittest.TestCase): def setUp(self): self.app = MagicMock() self.app.db = "database" - self.app.settings = {"pages": None} + self.app.settings = {"logged_in_pages": None, "logged_out_pages": None, "cookie_secret": test_cookie_secret} def test_base_handler(self): handler = BaseHandler(self.app, Mock()) self.assertEqual(handler.db, "database") - self.assertEqual(handler.pages, None) template = "file.html" with patch.object(RequestHandler, "render", return_value="a template") as r: - handler.render(template) - args, kwargs = r.call_args - self.assertTupleEqual((args, kwargs), ( - ("file.html",), {"pages": None})) + with patch.object(BaseHandler, 'get_current_user', return_value=None) as g: + handler.render(template) + args, kwargs = r.call_args + self.assertTupleEqual((args, kwargs), (("file.html",), {"pages": None})) +