diff --git a/example-config.py b/example-config.py index aff8ddc..c7aebc1 100644 --- a/example-config.py +++ b/example-config.py @@ -4,3 +4,4 @@ SQLALCHEMY_DATABASE_URI = 'sqlite:///wanikani.db' SECRET_KEY = "putabettersecretkeyhere" DEBUG = False PORT = 5000 +SQLALCHEMY_TRACK_MODIFICATIONS = False diff --git a/requirements.txt b/requirements.txt index 0b6eacf..d4e0a08 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ flask flask-login flask-sqlalchemy flask-wtf +flask-testing ujson \ No newline at end of file diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..17b1c27 --- /dev/null +++ b/tests.py @@ -0,0 +1,69 @@ +import unittest +from wanikaniburned import app, db, User +from flask.ext.testing import TestCase + + +class BaseTestCase(TestCase): + + def create_app(self): + app.config.update( + TESTING=True, + SQLALCHEMY_DATABASE_URI='sqlite:///:memory:', + SECRET_KEY="testkey", + WTF_CSRF_ENABLED=False, + PRESERVE_CONTEXT_ON_EXCEPTION=False, + HASH_ROUNDS=1 + ) + return app + + def setUp(self): + db.create_all() + + def tearDown(self): + db.session.remove() + db.drop_all() + + +class TestLogin(BaseTestCase): + + def login(self): + user = User('test', False) + return self.client.post('/', data={'api_key': user.api_key}) + + def test_user_login(self): + response = self.login() + self.assertRedirects(response, '/quiz') + + def test_user_logout(self): + response = self.login() + self.assertRedirects(response, '/quiz') + response = self.client.get('/logout') + self.assertRedirects(response, '/') + + def test_homepage_without_login(self): + response = self.client.get('/') + self.assert200(response) + self.assertTemplateUsed("welcome.html") + + def test_quiz_inaccessible_without_login(self): + response = self.client.get('/quiz') + self.assertRedirects(response, '/') + + def test_user_items_inaccessible_without_login(self): + response = self.client.get('/user_items') + self.assertRedirects(response, '/') + + def test_homepage_with_existing_login(self): + response = self.login() # Login + self.assertRedirects(response, '/quiz') + response = self.client.get('/') # Try to go back to the homepage + self.assertRedirects(response, '/quiz') + + def test_user_items_with_existing_login(self): + response = self.login() # Login + self.assertRedirects(response, '/quiz') + response = self.client.get('/user_items') + self.assert200(response) + +if __name__ == '__main__': + unittest.main() diff --git a/wanikaniburned.py b/wanikaniburned.py index 9faf65e..2514373 100644 --- a/wanikaniburned.py +++ b/wanikaniburned.py @@ -12,7 +12,11 @@ from wtforms import StringField from wtforms.validators import DataRequired app = flask.Flask(__name__) -app.config.from_pyfile('config.py') +app.config.update( + PORT=5000, + JSON_AS_ASCII=False +) +app.config.from_pyfile('config.py', silent=True) login_manager = LoginManager() login_manager.init_app(app) db = SQLAlchemy(app) @@ -33,12 +37,14 @@ class User(db.Model): gravatar = db.Column(db.String) last_updated = db.Column(db.DateTime) - def __init__(self, api_key): + def __init__(self, api_key, auto_init=True): self.api_key = api_key - self.last_updated = datetime.utcnow() - self.parse_radicals_and_userdata() - self.parse_kanji() - self.parse_vocabulary() + self.last_updated = datetime.min + if auto_init: + self.last_updated = datetime.utcnow() + self.parse_radicals_and_userdata() + self.parse_kanji() + self.parse_vocabulary() db.session.add(self) db.session.commit() @@ -117,14 +123,14 @@ def get_items_with_level_restriction(level_range, item_state, item_types): items = [] radical_count = 0 loads = json.loads - if 'radical' in item_types: + if 'radical' in item_types and current_user.radicals: items.extend({'item_type': 'radical', 'answer': item['meaning'], 'question': item['image'] if item['image'] else item['character']} for item in loads(current_user.radicals) if item['user_specific'] and item['user_specific']['srs'] in item_state and item['level'] in level_range) radical_count = len(items) kanji_count = 0 - if 'kanji' in item_types: + if 'kanji' in item_types and current_user.kanji: for item in filter((lambda x: x['user_specific'] and x['user_specific']['srs'] in item_state and x['level'] in level_range), loads(current_user.kanji)): items.extend([{'item_type': 'kanji', 'question': item['character'], @@ -134,7 +140,7 @@ def get_items_with_level_restriction(level_range, item_state, item_types): 'answer_type': 'eng'}]) kanji_count = int((len(items) - radical_count) / 2) vocabulary_count = 0 - if 'vocab' in item_types: + if 'vocab' in item_types and current_user.vocabulary: for item in filter((lambda x: x['user_specific'] and x['user_specific']['srs'] in item_state and x['level'] in level_range), loads(current_user.vocabulary)): items.extend([{'item_type': 'vocabulary', 'question': item['character'], 'answer': item['kana'], @@ -179,7 +185,7 @@ def show_home(): @app.route('/quiz') def show_quiz(): if not login_fresh(): - if User.query.get(current_user.api_key): + if not current_user.is_anonymous and User.query.get(current_user.api_key): confirm_login() return flask.render_template("quiz.html") else: @@ -224,11 +230,11 @@ def unauthorized(): return flask.redirect(flask.url_for('show_home')) +@app.template_filter('datetime_format') def datetime_format(input_data): return input_data.strftime("%d %B %Y %I:%M%p") if __name__ == '__main__': db.create_all() - app.jinja_env.filters['datetime_format'] = datetime_format app.run(threaded=True, port=app.config['PORT'])