Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit 604b0ff75466a076bf9b8b5dcc20bde5fa1cd088
Author: Bohuslav Kabrda <bkabrda(a)redhat.com>
Date: Thu Mar 28 15:46:04 2013 +0100
Start implementing admin section in frontend
---------------------------------------------------------------
coprs_frontend/coprs/__init__.py | 3 ++
coprs_frontend/coprs/helpers.py | 4 ++
coprs_frontend/coprs/templates/admin/index.html | 5 +++
coprs_frontend/coprs/templates/admin/layout.html | 8 +++++
coprs_frontend/coprs/views/admin_ns/__init__.py | 3 ++
.../coprs/views/admin_ns/admin_general.py | 11 +++++++
coprs_frontend/coprs/views/misc.py | 30 ++++++++++++++------
coprs_frontend/tests/coprs_test_case.py | 6 ++--
.../test_views/test_admin/test_admin_general.py | 20 +++++++++++++
9 files changed, 78 insertions(+), 12 deletions(-)
diff --git a/coprs_frontend/coprs/__init__.py b/coprs_frontend/coprs/__init__.py
index 6a9290c..103d7e1 100644
--- a/coprs_frontend/coprs/__init__.py
+++ b/coprs_frontend/coprs/__init__.py
@@ -25,6 +25,8 @@ import coprs.log
import coprs.models
import coprs.whoosheers
+from coprs.views import admin_ns
+from coprs.views.admin_ns import admin_general
from coprs.views import api_ns
from coprs.views.api_ns import api_general
from coprs.views import coprs_ns
@@ -35,6 +37,7 @@ from coprs.views.backend_ns import backend_general
from coprs.views import misc
app.register_blueprint(api_ns.api_ns)
+app.register_blueprint(admin_ns.admin_ns)
app.register_blueprint(coprs_ns.coprs_ns)
app.register_blueprint(misc.misc)
app.register_blueprint(backend_ns.backend_ns)
diff --git a/coprs_frontend/coprs/helpers.py b/coprs_frontend/coprs/helpers.py
index 15e942e..fdc87af 100644
--- a/coprs_frontend/coprs/helpers.py
+++ b/coprs_frontend/coprs/helpers.py
@@ -43,6 +43,10 @@ class BackendResultEnum(object):
__metaclass__ = EnumType
vals = {'waiting': 0, 'success': 1, 'failure': 2}
+class RoleEnum(object):
+ __metaclass__ = EnumType
+ vals = {'user': 0, 'admin': 1}
+
class Paginator(object):
def __init__(self, query, total_count, page = 1, per_page_override = None,
urls_count_override = None):
self.query = query
diff --git a/coprs_frontend/coprs/templates/admin/index.html
b/coprs_frontend/coprs/templates/admin/index.html
new file mode 100644
index 0000000..25562a2
--- /dev/null
+++ b/coprs_frontend/coprs/templates/admin/index.html
@@ -0,0 +1,5 @@
+{% extends "admin/layout.html" %}
+
+{% block admin_body %}
+Admin body
+{% endblock %}
diff --git a/coprs_frontend/coprs/templates/admin/layout.html
b/coprs_frontend/coprs/templates/admin/layout.html
new file mode 100644
index 0000000..336e077
--- /dev/null
+++ b/coprs_frontend/coprs/templates/admin/layout.html
@@ -0,0 +1,8 @@
+{% extends "layout.html" %}
+
+{% block title %}Coprs - Admin{% endblock %}
+
+{% block body %}
+Admin menu
+{% block admin_body %}{% endblock %}
+{% endblock %}
diff --git a/coprs_frontend/coprs/views/admin_ns/__init__.py
b/coprs_frontend/coprs/views/admin_ns/__init__.py
new file mode 100644
index 0000000..b7f5426
--- /dev/null
+++ b/coprs_frontend/coprs/views/admin_ns/__init__.py
@@ -0,0 +1,3 @@
+import flask
+
+admin_ns = flask.Blueprint('admin_ns', __name__, url_prefix = '/admin')
diff --git a/coprs_frontend/coprs/views/admin_ns/admin_general.py
b/coprs_frontend/coprs/views/admin_ns/admin_general.py
new file mode 100644
index 0000000..8252c5e
--- /dev/null
+++ b/coprs_frontend/coprs/views/admin_ns/admin_general.py
@@ -0,0 +1,11 @@
+import flask
+
+from coprs import helpers
+
+from coprs.views.admin_ns import admin_ns
+from coprs.views.misc import login_required
+
+(a)admin_ns.route('/')
+(a)login_required(role=helpers.RoleEnum('admin'))
+def admin_index():
+ return flask.render_template('admin/index.html')
diff --git a/coprs_frontend/coprs/views/misc.py b/coprs_frontend/coprs/views/misc.py
index 1c5a47c..7ffad6b 100644
--- a/coprs_frontend/coprs/views/misc.py
+++ b/coprs_frontend/coprs/views/misc.py
@@ -107,15 +107,27 @@ def api_login_required(f):
return decorated_function
-def login_required(f):
- @functools.wraps(f)
- def decorated_function(*args, **kwargs):
- if flask.g.user is None:
- return flask.redirect(flask.url_for('misc.login',
- next = flask.request.url))
- return f(*args, **kwargs)
- return decorated_function
-
+def login_required(role=helpers.RoleEnum('user')):
+ def view_wrapper(f):
+ @functools.wraps(f)
+ def decorated_function(*args, **kwargs):
+ if flask.g.user is None:
+ return flask.redirect(flask.url_for('misc.login',
+ next = flask.request.url))
+ if role == helpers.RoleEnum('admin') and not flask.g.user.admin:
+ flask.flash('You are not allowed to access admin section.')
+ return flask.redirect(flask.url_for('coprs_ns.coprs_show'))
+ return f(*args, **kwargs)
+ return decorated_function
+ # hack: if login_required is used without params, the "role" parameter
+ # is in fact the decorated function, so we need to return
+ # the wrapped function, not the wrapper
+ # proper solution would be to use login_required() with parentheses
+ # everywhere, even if they're empty - TODO
+ if callable(role):
+ return view_wrapper(role)
+ else:
+ return view_wrapper
# backend authentication
def backend_authenticated(f):
diff --git a/coprs_frontend/tests/coprs_test_case.py
b/coprs_frontend/tests/coprs_test_case.py
index 4f6043f..bea1f58 100644
--- a/coprs_frontend/tests/coprs_test_case.py
+++ b/coprs_frontend/tests/coprs_test_case.py
@@ -40,9 +40,9 @@ class CoprsTestCase(object):
@pytest.fixture
def f_users(self):
- self.u1 = models.User(openid_name =
u'http://user1.id.fedoraproject.org/';, proven = False, mail =
'user1(a)foo.bar')
- self.u2 = models.User(openid_name =
u'http://user2.id.fedoraproject.org/';, proven = False, mail =
'user2(a)spam.foo')
- self.u3 = models.User(openid_name =
u'http://user3.id.fedoraproject.org/';, proven = False, mail =
'baz(a)bar.bar')
+ self.u1 =
models.User(openid_name=u'http://user1.id.fedoraproject.org/';,
proven=False, admin=True, mail='user1(a)foo.bar')
+ self.u2 =
models.User(openid_name=u'http://user2.id.fedoraproject.org/';,
proven = False, mail='user2(a)spam.foo')
+ self.u3 =
models.User(openid_name=u'http://user3.id.fedoraproject.org/';,
proven=False, mail='baz(a)bar.bar')
self.db.session.add_all([self.u1, self.u2, self.u3])
diff --git a/coprs_frontend/tests/test_views/test_admin/test_admin_general.py
b/coprs_frontend/tests/test_views/test_admin/test_admin_general.py
new file mode 100644
index 0000000..1223934
--- /dev/null
+++ b/coprs_frontend/tests/test_views/test_admin/test_admin_general.py
@@ -0,0 +1,20 @@
+from tests.coprs_test_case import CoprsTestCase
+
+class TestAdminLogin(CoprsTestCase):
+ # TODO: test on something better then page title - maybe see rendered templates?
+ text_to_check = 'Coprs - Admin'
+ def test_nonadmin_cant_login(self, f_users, f_db):
+ with self.tc as c:
+ with c.session_transaction() as s:
+ s['openid'] = self.u2.openid_name
+
+ r = c.get('/admin/', follow_redirects=True)
+ assert self.text_to_check not in r.data
+
+ def test_admin_can_login(self, f_users, f_db):
+ with self.tc as c:
+ with c.session_transaction() as s:
+ s['openid'] = self.u1.openid_name
+
+ r = c.get('/admin/', follow_redirects=True)
+ assert self.text_to_check in r.data