Beispiel #1
0
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)
Beispiel #2
0
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()
Beispiel #3
0
 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)
Beispiel #4
0
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()
Beispiel #5
0
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()
Beispiel #6
0
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()
Beispiel #7
0
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()
Beispiel #8
0
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()
Beispiel #9
0
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