class TaskNewPostTest(unittest.TestCase): def setUp(self): self.pl = Mock(spec=InMemoryPersistenceLayer) self.ll = Mock(spec=LogicLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) self.admin = Mock(spec=User) def test_creates_new_task(self): # given request = generate_mock_request(method="POST") self.ll.get_lowest_order_num.return_value = 0 # when result = self.vl.task_new_post(request, self.admin) # then self.ll.create_new_task.assert_called() self.ll.do_add_tag_to_task.assert_not_called() self.r.url_for.assert_called() self.r.redirect.assert_called() self.assertIs(self.r.redirect.return_value, result) def test_tag_in_form_adds_tag(self): # given request = generate_mock_request(method="POST", form={'tags': 'tag1'}) self.ll.get_lowest_order_num.return_value = 0 # when result = self.vl.task_new_post(request, self.admin) # then self.ll.create_new_task.assert_called() self.ll.do_add_tag_to_task.assert_called_once_with( self.ll.create_new_task.return_value, 'tag1', self.admin) self.r.url_for.assert_called() self.r.redirect.assert_called() self.assertIs(self.r.redirect.return_value, result) def test_two_tags_in_form_adds_both_tags(self): # given request = generate_mock_request(method="POST", form={'tags': 'tag1,tag2'}) self.ll.get_lowest_order_num.return_value = 0 # when result = self.vl.task_new_post(request, self.admin) # then self.ll.create_new_task.assert_called() self.ll.do_add_tag_to_task.assert_any_call( self.ll.create_new_task.return_value, 'tag1', self.admin) self.ll.do_add_tag_to_task.assert_any_call( self.ll.create_new_task.return_value, 'tag2', self.admin) self.assertEqual(2, self.ll.do_add_tag_to_task.call_count) self.r.url_for.assert_called() self.r.redirect.assert_called() self.assertIs(self.r.redirect.return_value, result)
class AttachmentTest(unittest.TestCase): def setUp(self): self.pl = Mock(spec=InMemoryPersistenceLayer) self.ll = Mock(spec=LogicLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) self.admin = Mock(spec=User) def test_gets_attachment(self): # given upload_folder = '/path/to/uploads' self.ll.upload_folder = upload_folder attachment_id = 123 attachment_path = 'this/is/the/path' attachment = Mock(spec=Attachment) attachment.id = attachment_id attachment.path = attachment_path self.ll.pl_get_attachment.return_value = attachment request = generate_mock_request(method="GET") # when result = self.vl.attachment(request, self.admin, attachment_id, 'name') # then self.r.send_from_directory.assert_called_once_with( upload_folder, attachment_path) # and self.ll.pl_get_attachment.assert_called_once_with(attachment_id) self.pl.get_attachment.assert_not_called() self.assertIs(self.r.send_from_directory.return_value, result) def test_attachment_not_found_raises(self): # given self.ll.pl_get_attachment.return_value = None request = generate_mock_request(method="GET") attachment_id = 123 # expect with self.assertRaises(NotFound) as cm: self.vl.attachment(request, self.admin, attachment_id, 'name') # then self.assertEqual("No attachment found for the id '123'", cm.exception.description) self.r.send_from_directory.assert_not_called() # and self.ll.pl_get_attachment.assert_called_once_with(attachment_id) self.pl.get_attachment.assert_not_called()
def setUp(self): self.ll = Mock(spec=LogicLayer) self.pl = Mock(spec=InMemoryPersistenceLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r)
class ImportTest(unittest.TestCase): def setUp(self): self.ll = Mock(spec=LogicLayer) self.pl = Mock(spec=InMemoryPersistenceLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) def test_imports_data_from_file(self): # given src = '''{"tasks":[{ "id": 1, "summary":"summary" }]}''' src_dict = { "tasks": [{ "id": 1, "summary": "summary", }] } form = {} files = {'file': MockFileObject(filename='', content=src)} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.import_(request, admin) # then self.ll.do_import_data.assert_called_once_with(src_dict) # and self.r.url_for.assert_called_once_with('index') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_imports_data_from_form(self): # given src = '''{"tasks":[{ "id": 1, "summary":"summary" }]}''' src_dict = { "tasks": [{ "id": 1, "summary": "summary", }] } form = {'raw': src} files = {} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.import_(request, admin) # then self.ll.do_import_data.assert_called_once_with(src_dict) # and self.r.url_for.assert_called_once_with('index') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_get_request_returns_template(self): # given request = generate_mock_request(method='GET') admin = self.pl.create_user('admin', is_admin=True) # self.r.render_template # when result = self.vl.import_(request, admin) # then self.r.render_template.assert_called_once_with('import.t.html') self.assertIs(self.r.render_template.return_value, result) # and self.r.url_for.assert_not_called() self.r.redirect.assert_not_called()
class AttachmentNewTest(unittest.TestCase): def setUp(self): self.ll = Mock(spec=LogicLayer) self.pl = Mock(spec=InMemoryPersistenceLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) def test_creates_new_attachment(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id} f = MockFileObject('/filename.txt') files = {'filename': f} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.attachment_new(request, admin) # then self.ll.create_new_attachment.assert_called_once_with(task.id, f, '', admin, timestamp=None) # and self.r.url_for.assert_called_once_with('view_task', id=task.id) self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_description_none_yields_none(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': None} f = MockFileObject('/filename.txt') files = {'filename': f} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.attachment_new(request, admin) # then self.ll.create_new_attachment.assert_called_once_with(task.id, f, None, admin, timestamp=None) # and self.r.url_for.assert_called_once_with('view_task', id=task.id) self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_empty_description_yields_empty_description(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': ''} f = MockFileObject('/filename.txt') files = {'filename': f} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.attachment_new(request, admin) # then self.ll.create_new_attachment.assert_called_once_with(task.id, f, '', admin, timestamp=None) # and self.r.url_for.assert_called_once_with('view_task', id=task.id) self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_description_sets_description(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': 'asdf'} f = MockFileObject('/filename.txt') files = {'filename': f} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # when result = self.vl.attachment_new(request, admin) # then self.ll.create_new_attachment.assert_called_once_with(task.id, f, 'asdf', admin, timestamp=None) # and self.r.url_for.assert_called_once_with('view_task', id=task.id) self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_null_file_object_raises(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': 'asdf'} files = {'filename': None} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # expect self.assertRaises(BadRequest, self.vl.attachment_new, request, admin) # and self.r.redirect.assert_not_called() def test_null_filename_raises(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': 'asdf'} files = {'filename': MockFileObject(None)} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # expect self.assertRaises(BadRequest, self.vl.attachment_new, request, admin) # and self.r.redirect.assert_not_called() def test_empty_filename_raises(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': 'asdf'} files = {'filename': MockFileObject('')} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # expect self.assertRaises(BadRequest, self.vl.attachment_new, request, admin) # and self.r.redirect.assert_not_called() def test_extension_not_allowed_raises(self): # given task = Mock(spec=Task) task.id = 123 form = {'task_id': task.id, 'description': 'asdf'} files = {'filename': MockFileObject('/filename.exe')} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) self.ll.allowed_file.return_value = False # expect self.assertRaises(BadRequest, self.vl.attachment_new, request, admin) # and self.r.redirect.assert_not_called() def test_task_id_not_sepcified_raises(self): # given task = Mock(spec=Task) task.id = 123 form = {} files = {'filename': MockFileObject('/filename.exe')} request = generate_mock_request(form=form, files=files) admin = self.pl.create_user('admin', is_admin=True) # expect self.assertRaises(BadRequest, self.vl.attachment_new, request, admin) # and self.r.redirect.assert_not_called()
class TaskTest(unittest.TestCase): def setUp(self): self.ll = Mock(spec=LogicLayer) self.return_value = { 'task': None, 'descendants': [], 'pager': None, } self.ll.get_task_data = Mock(return_value=self.return_value) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) def test_gets_task_data_from_logic_layer(self): # given request = generate_mock_request(args={}, cookies={}) user = Mock() TASK_ID = 1 # when result = self.vl.task(request, user, TASK_ID) # then self.assertIsNotNone(result) self.ll.get_task_data.assert_called_with(TASK_ID, user, include_deleted=None, include_done=None, page_num=1, tasks_per_page=20) self.r.render_template.assert_called() def test_page_num_not_int_defaults_to_one(self): # given request = generate_mock_request(args={'page': 'asdf'}, cookies={}) user = Mock() TASK_ID = 1 # when result = self.vl.task(request, user, TASK_ID) # then self.assertIsNotNone(result) self.ll.get_task_data.assert_called_with(TASK_ID, user, include_deleted=None, include_done=None, page_num=1, tasks_per_page=20) self.r.render_template.assert_called() def test_task_per_page_not_int_default_to_twenty(self): # given request = generate_mock_request(args={'per_page': 'asdf'}, cookies={}) user = Mock() TASK_ID = 1 # when result = self.vl.task(request, user, TASK_ID) # then self.assertIsNotNone(result) self.ll.get_task_data.assert_called_with(TASK_ID, user, include_deleted=None, include_done=None, page_num=1, tasks_per_page=20) self.r.render_template.assert_called()
class LoginTest(unittest.TestCase): def setUp(self): self.pl = Mock(spec=InMemoryPersistenceLayer) self.ll = Mock(spec=LogicLayer) self.r = Mock(spec=DefaultRenderer) self.ls = Mock(spec=DefaultLoginSource) self.vl = ViewLayer(self.ll, None, renderer=self.r, login_src=self.ls) self.admin = Mock(spec=User) def test_renders_template_on_get(self): # given request = generate_mock_request(method="GET") # when result = self.vl.login(request, self.admin) # then self.r.render_template.assert_called_once_with('login.t.html') self.ls.login_user.assert_not_called() self.assertIs(self.r.render_template.return_value, result) # and self.ll.pl_get_user_by_email.assert_not_called() self.pl.get_user_by_email.assert_not_called() self.r.flash.assert_not_called() self.r.redirect.assert_not_called() self.r.url_for.assert_not_called() def test_logs_in_user(self): # given email = '*****@*****.**' password = '******' hashed_password = '******' user = Mock(spec=User) user.email = email user.hashed_password = hashed_password self.ls.check_password_hash.return_value = True self.ll.pl_get_user_by_email.return_value = user request = generate_mock_request(method="POST", form={ 'email': email, 'password': password }) # when result = self.vl.login(request, self.admin) # then self.ls.login_user.assert_called_once_with(user) self.r.url_for.assert_called_once_with('index') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) # and self.r.flash.assert_called_once_with('Logged in successfully') self.ll.pl_get_user_by_email.assert_called_once_with(email) self.pl.get_user_by_email.assert_not_called() self.ls.check_password_hash.assert_called_once_with( hashed_password, password) self.r.render_template.assert_not_called() def test_email_not_found_redirects(self): # given email = '*****@*****.**' password = '******' self.ls.check_password_hash.return_value = True self.ll.pl_get_user_by_email.return_value = None # request = generate_mock_request(method="POST", form={ 'email': email, 'password': password }) # when result = self.vl.login(request, self.admin) # then self.ls.login_user.assert_not_called() self.ll.pl_get_user_by_email.assert_called_once_with(email) self.pl.get_user_by_email.assert_not_called() self.r.flash.assert_called_once_with('Username or Password is invalid', 'error') self.r.url_for.assert_called_once_with('login') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) # and self.ls.check_password_hash.assert_not_called() self.r.render_template.assert_not_called() def test_hashed_password_none_redirects(self): # given email = '*****@*****.**' password = '******' hashed_password = None # user = Mock(spec=User) user.email = email user.hashed_password = hashed_password self.ls.check_password_hash.return_value = True self.ll.pl_get_user_by_email.return_value = user request = generate_mock_request(method="POST", form={ 'email': email, 'password': password }) # when result = self.vl.login(request, self.admin) # then self.ls.login_user.assert_not_called() self.ll.pl_get_user_by_email.assert_called_once_with(email) self.pl.get_user_by_email.assert_not_called() self.r.flash.assert_called_once_with('Username or Password is invalid', 'error') self.r.url_for.assert_called_once_with('login') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) # and self.ls.check_password_hash.assert_not_called() self.r.render_template.assert_not_called() def test_hashed_password_empty_redirects(self): # given email = '*****@*****.**' password = '******' hashed_password = '' # user = Mock(spec=User) user.email = email user.hashed_password = hashed_password self.ls.check_password_hash.return_value = True self.ll.pl_get_user_by_email.return_value = user request = generate_mock_request(method="POST", form={ 'email': email, 'password': password }) # when result = self.vl.login(request, self.admin) # then self.ls.login_user.assert_not_called() self.ll.pl_get_user_by_email.assert_called_once_with(email) self.pl.get_user_by_email.assert_not_called() self.r.flash.assert_called_once_with('Username or Password is invalid', 'error') self.r.url_for.assert_called_once_with('login') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) # and self.ls.check_password_hash.assert_not_called() self.r.render_template.assert_not_called() def test_hashed_password_does_not_match_redirects(self): # given email = '*****@*****.**' password = '******' hashed_password = '******' user = Mock(spec=User) user.email = email user.hashed_password = hashed_password self.ls.check_password_hash.return_value = False # self.ll.pl_get_user_by_email.return_value = user request = generate_mock_request(method="POST", form={ 'email': email, 'password': password }) # when result = self.vl.login(request, self.admin) # then self.ls.login_user.assert_not_called() self.ll.pl_get_user_by_email.assert_called_once_with(email) self.pl.get_user_by_email.assert_not_called() self.r.flash.assert_called_once_with('Username or Password is invalid', 'error') self.r.url_for.assert_called_once_with('login') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) self.ls.check_password_hash.assert_called_once_with( hashed_password, password) # and self.r.render_template.assert_not_called()
class TaskPurgeTest(unittest.TestCase): def setUp(self): self.pl = Mock(spec=InMemoryPersistenceLayer) self.ll = Mock(spec=LogicLayer) self.r = Mock(spec=DefaultRenderer) self.vl = ViewLayer(self.ll, None, renderer=self.r) self.admin = Mock(spec=User) def test_purges_deleted_task(self): # given task = Mock(spec=Task) task.is_deleted = True self.ll.pl_get_task.return_value = task request = generate_mock_request(method="GET") task_id = 123 # when result = self.vl.task_purge(request, self.admin, task_id) # then self.ll.purge_task.assert_called_once_with(task, self.admin) # and self.ll.pl_get_task.assert_called_once_with(task_id) self.pl.get_task.assert_not_called() self.r.url_for.assert_called_once_with('index') self.r.redirect.assert_called_once_with(self.r.url_for.return_value) self.assertIs(self.r.redirect.return_value, result) def test_task_not_found_raises(self): # given self.ll.pl_get_task.return_value = None request = generate_mock_request(method="GET") task_id = 123 # expect with self.assertRaises(NotFound) as cm: self.vl.task_purge(request, self.admin, task_id) # then self.assertEqual("No task found for the id '123'", cm.exception.description) self.ll.purge_task.assert_not_called() # and self.ll.pl_get_task.assert_called_once_with(task_id) self.pl.get_task.assert_not_called() self.r.url_for.assert_not_called() self.r.redirect.assert_not_called() def test_task_not_deleted_raises(self): # given task = Mock(spec=Task) task.is_deleted = False self.ll.pl_get_task.return_value = task request = generate_mock_request(method="GET") task_id = 123 # expect with self.assertRaises(BadRequest) as cm: self.vl.task_purge(request, self.admin, task_id) # then self.assertEqual("Indicated task (id 123) has not been deleted.", cm.exception.description) self.ll.purge_task.assert_not_called() # and self.ll.pl_get_task.assert_called_once_with(task_id) self.pl.get_task.assert_not_called() self.r.url_for.assert_not_called() self.r.redirect.assert_not_called()
def generate_app(db_uri=None, db_options=None, upload_folder=None, secret_key=None, allowed_extensions=None, ll=None, vl=None, pl=None, flask_configs=None, disable_admin_check=False): app = Flask(__name__) app.config['UPLOAD_FOLDER'] = upload_folder app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False if flask_configs: for k, v in flask_configs.items(): app.config[k] = v app.secret_key = secret_key # ALLOWED_EXTENSIONS = set(ext for ext in re.split('[\s,]+', # allowed_extensions) # if ext is not None and ext != '') login_manager = LoginManager() login_manager.init_app(app) app.login_manager = login_manager login_manager.login_view = 'login' bcrypt = Bcrypt(app) app.bcrypt = bcrypt if pl is None: app.config['SQLALCHEMY_DATABASE_URI'] = db_uri opts = split_db_options(db_options) app.config['SQLALCHEMY_ENGINE_OPTIONS'] = opts db = SQLAlchemy(app) pl = SqlAlchemyPersistenceLayer(db) app.pl = pl class Options(object): @staticmethod def get(key, default_value=None): option = pl.get_option(key) if option is None: return default_value return option.value @staticmethod def get_title(): return Options.get('title', 'Tudor') @staticmethod def get_revision(): return __revision__ @staticmethod def get_version(): return __version__ @staticmethod def get_author(): return Options.get('author', 'the author') @staticmethod def get_user(): if current_user is None: return pl.get_guest_user() try: user_id = current_user.id return pl.get_user(user_id) except AttributeError: return pl.get_guest_user() app.Options = Options if ll is None: ll = LogicLayer(upload_folder, allowed_extensions, pl) app.ll = ll if vl is None: vl = ViewLayer(ll, app.bcrypt) app.vl = vl # Flask setup functions @login_manager.user_loader def load_user(userid): return pl.get_user_by_email(userid) @login_manager.request_loader def load_user_with_basic_auth(request): api_key = request.headers.get('Authorization') if api_key: api_key = api_key.replace('Basic ', '', 1) api_key = base64.b64decode(api_key).decode('utf-8') email, password = api_key.split(':', 1) user = pl.get_user_by_email(email) if user is None: return None if user.hashed_password is None or user.hashed_password == '': return None if not bcrypt.check_password_hash(user.hashed_password, password): return None return user def admin_required(func): @wraps(func) def decorated_view(*args, **kwargs): if not disable_admin_check and not current_user.is_admin: return ('You are not authorized to view this page', 403) return func(*args, **kwargs) return decorated_view @app.context_processor def setup_options(): return {'opts': Options} # View Functions @app.route('/') @login_required def index(): return vl.index(request, Options.get_user()) @app.route('/hierarchy') @login_required def hierarchy(): return vl.hierarchy(request, Options.get_user()) @app.route('/deadlines') @login_required def deadlines(): return vl.deadlines(request, Options.get_user()) @app.route('/task/new', methods=['GET']) @login_required def get_new_task(): return vl.task_new_get(request, Options.get_user()) @app.route('/task/new', methods=['POST']) @login_required def new_task(): return vl.task_new_post(request, Options.get_user()) @app.route('/task/<int:id>/mark_done') @login_required def task_done(id): return vl.task_mark_done(request, Options.get_user(), id) @app.route('/task/<int:id>/mark_undone') @login_required def task_undo(id): return vl.task_mark_undone(request, Options.get_user(), id) @app.route('/task/<int:id>/delete') @login_required def delete_task(id): return vl.task_delete(request, Options.get_user(), id) @app.route('/task/<int:id>/undelete') @login_required def undelete_task(id): return vl.task_undelete(request, Options.get_user(), id) @app.route('/task/<int:id>/purge') @login_required @admin_required def purge_task(id): return vl.task_purge(request, Options.get_user(), id) @app.route('/purge_all') @login_required @admin_required def purge_deleted_tasks(): return vl.purge_all(request, Options.get_user()) @app.route('/task/<int:id>') def view_task(id): return vl.task(request, Options.get_user(), id) @app.route('/task/<int:id>/hierarchy') def view_task_hierarchy(id): return vl.task_hierarchy(request, Options.get_user(), id) @app.route('/note/new', methods=['POST']) @login_required def new_note(): return vl.note_new_post(request, Options.get_user()) @app.route('/task/<int:id>/edit', methods=['GET', 'POST']) @login_required def edit_task(id): return vl.task_edit(request, Options.get_user(), id) @app.route('/attachment/new', methods=['POST']) @login_required def new_attachment(): return vl.attachment_new(request, Options.get_user(), timestamp=datetime.utcnow()) @app.route('/attachment/<int:aid>', defaults={'x': 'x'}) @app.route('/attachment/<int:aid>/', defaults={'x': 'x'}) @app.route('/attachment/<int:aid>/<path:x>') @login_required def get_attachment(aid, x): return vl.attachment(request, Options.get_user(), aid, x) @app.route('/task/<int:id>/up') @login_required def move_task_up(id): return vl.task_up(request, Options.get_user(), id) @app.route('/task/<int:id>/top') @login_required def move_task_to_top(id): return vl.task_top(request, Options.get_user(), id) @app.route('/task/<int:id>/down') @login_required def move_task_down(id): return vl.task_down(request, Options.get_user(), id) @app.route('/task/<int:id>/bottom') @login_required def move_task_to_bottom(id): return vl.task_bottom(request, Options.get_user(), id) @app.route('/long_order_change', methods=['POST']) @login_required def long_order_change(): return vl.long_order_change(request, Options.get_user()) @app.route('/task/<int:id>/add_tag', methods=['GET', 'POST']) @login_required def add_tag_to_task(id): return vl.task_add_tag(request, Options.get_user(), id) @app.route('/task/<int:id>/delete_tag', methods=['GET', 'POST'], defaults={'tag_id': None}) @app.route('/task/<int:id>/delete_tag/', methods=['GET', 'POST'], defaults={'tag_id': None}) @app.route('/task/<int:id>/delete_tag/<tag_id>', methods=['GET', 'POST']) @login_required def delete_tag_from_task(id, tag_id): return vl.task_delete_tag(request, Options.get_user(), id, tag_id) @app.route('/task/<int:task_id>/authorize_user', methods=['GET', 'POST']) @login_required def authorize_user_for_task(task_id): return vl.task_authorize_user(request, Options.get_user(), task_id) @app.route('/task/<int:task_id>/pick_user') @login_required def pick_user_to_authorize(task_id): return vl.task_pick_user(request, Options.get_user(), task_id) @app.route('/task/<int:task_id>/authorize_user/<int:user_id>', methods=['GET', 'POST']) @login_required def authorize_picked_user_for_task(task_id, user_id): return vl.task_authorize_user_user(request, Options.get_user(), task_id, user_id) @app.route('/task/<int:task_id>/deauthorize_user', methods=['GET', 'POST'], defaults={'user_id': None}) @app.route('/task/<int:task_id>/deauthorize_user/', methods=['GET', 'POST'], defaults={'user_id': None}) @app.route('/task/<int:task_id>/deauthorize_user/<int:user_id>', methods=['GET', 'POST']) @login_required def deauthorize_user_for_task(task_id, user_id): return vl.task_deauthorize_user(request, Options.get_user(), task_id, user_id) @app.route('/login', methods=['GET', 'POST']) def login(): return vl.login(request, Options.get_user()) @app.route('/logout') def logout(): return vl.logout(request, Options.get_user()) @app.route('/users', methods=['GET', 'POST']) @login_required @admin_required def list_users(): return vl.users(request, Options.get_user()) @app.route('/users/<int:user_id>', methods=['GET']) @login_required def view_user(user_id): return vl.users_user_get(request, Options.get_user(), user_id) @app.route('/show_hide_deleted') @login_required def show_hide_deleted(): return vl.show_hide_deleted(request, Options.get_user()) @app.route('/show_hide_done') @login_required def show_hide_done(): return vl.show_hide_done(request, Options.get_user()) @app.route('/options', methods=['GET', 'POST']) @login_required @admin_required def view_options(): return vl.options(request, Options.get_user()) @app.route('/option/<path:key>/delete') @login_required @admin_required def delete_option(key): return vl.option_delete(request, Options.get_user(), key) @app.route('/reset_order_nums') @login_required def reset_order_nums(): return vl.reset_order_nums(request, Options.get_user()) @app.route('/export', methods=['GET', 'POST']) @login_required @admin_required def export_data(): return vl.export(request, Options.get_user()) @app.route('/import', methods=['GET', 'POST']) @login_required @admin_required def import_data(): return vl.import_(request, Options.get_user()) @app.route('/task_crud', methods=['GET', 'POST']) @login_required @admin_required def task_crud(): return vl.task_crud(request, Options.get_user()) @app.route('/tags') @app.route('/tags/') @login_required def list_tags(): return vl.tags(request, Options.get_user()) @app.route('/tags/<int:id>') @login_required def view_tag(id): return vl.tags_id_get(request, Options.get_user(), id) @app.route('/tags/<int:id>/edit', methods=['GET', 'POST']) @login_required def edit_tag(id): return vl.tags_id_edit(request, Options.get_user(), id) @app.route('/task/<int:id>/convert_to_tag') @login_required def convert_task_to_tag(id): return vl.task_id_convert_to_tag(request, Options.get_user(), id) @app.route('/search', methods=['GET', 'POST'], defaults={'search_query': None}) @app.route('/search/', methods=['GET', 'POST'], defaults={'search_query': None}) @app.route('/search/<search_query>', methods=['GET']) @login_required def search(search_query): return vl.search(request, Options.get_user(), search_query) @app.route('/task/<int:task_id>/add_dependee', methods=['GET', 'POST'], defaults={'dependee_id': None}) @app.route('/task/<int:task_id>/add_dependee/', methods=['GET', 'POST'], defaults={'dependee_id': None}) @app.route('/task/<int:task_id>/add_dependee/<int:dependee_id>', methods=['GET', 'POST']) @login_required def add_dependee_to_task(task_id, dependee_id): return vl.task_id_add_dependee(request, Options.get_user(), task_id, dependee_id) @app.route('/task/<int:task_id>/remove_dependee', methods=['GET', 'POST'], defaults={'dependee_id': None}) @app.route('/task/<int:task_id>/remove_dependee/', methods=['GET', 'POST'], defaults={'dependee_id': None}) @app.route('/task/<int:task_id>/remove_dependee/<int:dependee_id>', methods=['GET', 'POST']) @login_required def remove_dependee_from_task(task_id, dependee_id): return vl.task_id_remove_dependee(request, Options.get_user(), task_id, dependee_id) @app.route('/task/<int:task_id>/add_dependant', methods=['GET', 'POST'], defaults={'dependant_id': None}) @app.route('/task/<int:task_id>/add_dependant/', methods=['GET', 'POST'], defaults={'dependant_id': None}) @app.route('/task/<int:task_id>/add_dependant/<int:dependant_id>', methods=['GET', 'POST']) @login_required def add_dependant_to_task(task_id, dependant_id): return vl.task_id_add_dependant(request, Options.get_user(), task_id, dependant_id) @app.route('/task/<int:task_id>/remove_dependant', methods=['GET', 'POST'], defaults={'dependant_id': None}) @app.route('/task/<int:task_id>/remove_dependant/', methods=['GET', 'POST'], defaults={'dependant_id': None}) @app.route('/task/<int:task_id>/remove_dependant/<int:dependant_id>', methods=['GET', 'POST']) @login_required def remove_dependant_from_task(task_id, dependant_id): return vl.task_id_remove_dependant(request, Options.get_user(), task_id, dependant_id) @app.route('/task/<int:task_id>/add_prioritize_before', methods=['GET', 'POST'], defaults={'prioritize_before_id': None}) @app.route('/task/<int:task_id>/add_prioritize_before/', methods=['GET', 'POST'], defaults={'prioritize_before_id': None}) @app.route( '/task/<int:task_id>/add_prioritize_before/<int:prioritize_before_id>', methods=['GET', 'POST']) @login_required def add_prioritize_before_to_task(task_id, prioritize_before_id): return vl.task_id_add_prioritize_before(request, Options.get_user(), task_id, prioritize_before_id) @app.route('/task/<int:task_id>/remove_prioritize_before', methods=['GET', 'POST'], defaults={'prioritize_before_id': None}) @app.route('/task/<int:task_id>/remove_prioritize_before/', methods=['GET', 'POST'], defaults={'prioritize_before_id': None}) @app.route( '/task/<int:task_id>/remove_prioritize_before/' '<int:prioritize_before_id>', methods=['GET', 'POST']) @login_required def remove_prioritize_before_from_task(task_id, prioritize_before_id): return vl.task_id_remove_prioritize_before(request, Options.get_user(), task_id, prioritize_before_id) @app.route('/task/<int:task_id>/add_prioritize_after', methods=['GET', 'POST'], defaults={'prioritize_after_id': None}) @app.route('/task/<int:task_id>/add_prioritize_after/', methods=['GET', 'POST'], defaults={'prioritize_after_id': None}) @app.route( '/task/<int:task_id>/add_prioritize_after/<int:prioritize_after_id>', methods=['GET', 'POST']) @login_required def add_prioritize_after_to_task(task_id, prioritize_after_id): return vl.task_id_add_prioritize_after(request, Options.get_user(), task_id, prioritize_after_id) @app.route('/task/<int:task_id>/remove_prioritize_after', methods=['GET', 'POST'], defaults={'prioritize_after_id': None}) @app.route('/task/<int:task_id>/remove_prioritize_after/', methods=['GET', 'POST'], defaults={'prioritize_after_id': None}) @app.route( '/task/<int:task_id>/remove_prioritize_after/' '<int:prioritize_after_id>', methods=['GET', 'POST']) @login_required def remove_prioritize_after_from_task(task_id, prioritize_after_id): return vl.task_id_remove_prioritize_after(request, Options.get_user(), task_id, prioritize_after_id) @app.template_filter(name='gfm') def render_gfm(s): output = markdown.markdown(s, extensions=['gfm']) moutput = Markup(output) return moutput return app