aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wqflask/wqflask/model.py44
-rw-r--r--wqflask/wqflask/templates/admin/group_manager.html12
-rw-r--r--wqflask/wqflask/templates/admin/ind_user_manager.html33
-rw-r--r--wqflask/wqflask/templates/admin/user_manager.html9
-rw-r--r--wqflask/wqflask/templates/base.html2
-rw-r--r--wqflask/wqflask/user_manager.py58
6 files changed, 125 insertions, 33 deletions
diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py
index cf9e58e1..b508f18e 100644
--- a/wqflask/wqflask/model.py
+++ b/wqflask/wqflask/model.py
@@ -23,11 +23,11 @@ from wqflask.database import Base, init_db
# Column('user_id', Integer(), ForeignKey('user.the_id')),
# Column('role_id', Integer(), ForeignKey('role.the_id')))
-class Role(Base):
- __tablename__ = "role"
- id = Column(Unicode(36), primary_key=True, default=lambda: unicode(uuid.uuid4()))
- name = Column(Unicode(80), unique=True, nullable=False)
- description = Column(Unicode(255))
+#class Role(Base):
+# __tablename__ = "role"
+# id = Column(Unicode(36), primary_key=True, default=lambda: unicode(uuid.uuid4()))
+# name = Column(Unicode(80), unique=True, nullable=False)
+# description = Column(Unicode(255))
class User(Base):
__tablename__ = "user"
@@ -46,9 +46,13 @@ class User(Base):
confirmed = Column(Text) # json detailing when they confirmed, etc.
+ superuser = Column(Text) # json detailing when they became a superuser, otherwise empty
+ # if not superuser
+
logins = relationship("Login",
order_by="desc(Login.timestamp)",
- lazy='dynamic' # Necessary for filter in login_count
+ lazy='dynamic', # Necessary for filter in login_count
+ foreign_keys="Login.user",
)
user_collections = relationship("UserCollection",
@@ -56,6 +60,14 @@ class User(Base):
)
@property
+ def name_and_org(self):
+ """Nice shortcut for printing out who the user is"""
+ if self.organization:
+ return "{} from {}".format(self.full_name, self.organization)
+ else:
+ return self.full_name
+
+ @property
def login_count(self):
return self.logins.filter_by(successful=True).count()
@@ -69,6 +81,23 @@ class User(Base):
return None
@property
+ def superuser_info(self):
+ if self.superuser:
+ return json.loads(self.superuser)
+ else:
+ return None
+
+ @property
+ def crowner(self):
+ """If made superuser, returns object of person who did the crowning"""
+ if self.superuser:
+ superuser_info = json.loads(self.superuser)
+ crowner = User.query.get(superuser_info['crowned_by'])
+ return crowner
+ else:
+ return None
+
+ @property
def most_recent_login(self):
try:
return self.logins[0]
@@ -89,6 +118,9 @@ class Login(Base):
successful = Column(Boolean(), nullable=False) # False if wrong password was entered
session_id = Column(Text) # Set only if successfully logged in, otherwise should be blank
+ # Set to user who assumes identity if this was a login for debugging purposes by a superuser
+ assumed_by = Column(Unicode(36), ForeignKey('user.id'))
+
def __init__(self, user):
self.user = user.id
self.ip_address = request.remote_addr
diff --git a/wqflask/wqflask/templates/admin/group_manager.html b/wqflask/wqflask/templates/admin/group_manager.html
index df3eda33..ea9026a6 100644
--- a/wqflask/wqflask/templates/admin/group_manager.html
+++ b/wqflask/wqflask/templates/admin/group_manager.html
@@ -2,11 +2,7 @@
{% block title %}Group Manager{% endblock %}
{% block content %}
<!-- Start of body -->
- <header class="jumbotron subhead" id="overview">
- <div class="container">
- <h1>Group Manager</h1>
- </div>
- </header>
+ {{ header("List of groups", "" )}}
<div class="container">
<div class="page-header">
@@ -48,13 +44,13 @@
{% endblock %}
-{% block js %}
+{% block js %}
<script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script>
<script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script>
<script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script>
<script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script>
<script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script>
-
+
<script type="text/javascript" charset="utf-8">
$(document).ready( function () {
console.time("Creating table");
@@ -80,4 +76,4 @@
console.timeEnd("Creating table");
});
</script>
-{% endblock %} \ No newline at end of file
+{% endblock %}
diff --git a/wqflask/wqflask/templates/admin/ind_user_manager.html b/wqflask/wqflask/templates/admin/ind_user_manager.html
index 03a86e63..dc24bca5 100644
--- a/wqflask/wqflask/templates/admin/ind_user_manager.html
+++ b/wqflask/wqflask/templates/admin/ind_user_manager.html
@@ -2,11 +2,6 @@
{% block title %}User Manager{% endblock %}
{% block content %}
<!-- Start of body -->
- <header class="jumbotron subhead" id="overview">
- <div class="container">
- <h1>User Manager</h1>
- </div>
- </header>
<div class="container">
<div class="page-header">
@@ -21,7 +16,7 @@
{% endif %}
</div>
-
+ {{ flash_me() }}
<table class="table table-hover">
<!-- <thead>
@@ -53,6 +48,25 @@
</tr>
<tr>
+ <td>Superuser</td>
+
+ {% if user.superuser %}
+ <td>Made supervisor {{ timeago(user.superuser_info['timestamp'] + "Z") }} by
+ {{ user.crowner.name_and_org }}.
+ </td>
+ {% else %}
+ <td>
+ <span>
+ <a class="btn btn-danger btn-small" href={{"/manage/make_superuser?user_id={}".format(user.id)}}>
+ Make Superuser
+ </a>
+ </span>
+ </td>
+ {% endif %}
+ </tr>
+
+
+ <tr>
<td>Most recent login</td>
{% if user.most_recent_login %}
<td>{{ timeago(user.most_recent_login.timestamp.isoformat() + "Z") }} from {{ user.most_recent_login.ip_address }}</td>
@@ -70,6 +84,13 @@
<td>Number of logins</td>
<td>{{ user.login_count }}</td>
</tr>-->
+ <tr>
+ <td colspan="2">
+ <a class="btn btn-danger btn-small" href={{"/manage/assume_identity?user_id={}".format(user.id)}}>
+ Become this user for debugging
+ </a>
+ </td>
+ </tr>
</table>
diff --git a/wqflask/wqflask/templates/admin/user_manager.html b/wqflask/wqflask/templates/admin/user_manager.html
index 1308ff4b..2b6c1b2b 100644
--- a/wqflask/wqflask/templates/admin/user_manager.html
+++ b/wqflask/wqflask/templates/admin/user_manager.html
@@ -2,11 +2,8 @@
{% block title %}User Manager{% endblock %}
{% block content %}
<!-- Start of body -->
- <header class="jumbotron subhead" id="overview">
- <div class="container">
- <h1>User Manager</h1>
- </div>
- </header>
+ {{ header("List of users", "" )}}
+
<div class="container">
<div class="page-header">
@@ -20,6 +17,7 @@
<th>Organization</th>
<th>Active</th>
<th>Confirmed</th>
+ <th>Superuser</th>
</tr>
</thead>
{% for user in users %}
@@ -30,6 +28,7 @@
<td>{{ user.organization }}</td>
<td>{{ 'Yes' if user.active else 'No' }}</td>
<td title="{{ user.confirmed }}">{{ 'True' if user.confirmed else 'False' }}</td>
+ <td title="{{ user.superuser }}">{{ 'True' if user.superuser else 'False' }}</td>
</tr>
{% endfor %}
</table>
diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html
index d52286f1..ea6db646 100644
--- a/wqflask/wqflask/templates/base.html
+++ b/wqflask/wqflask/templates/base.html
@@ -105,7 +105,7 @@
</li>
<li class="">
{% if g.user_session.logged_in %}
- <a id="login_out" href="/n/logout">Sign out</a>
+ <a id="login_out" title="Signed in as {{ g.user_session.user_ob.name_and_org }}." href="/n/logout">Sign out</a>
{% else %}
<a id="login_in" href="/n/login">Sign in</a>
{% endif %}
diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py
index 913ff231..c092771c 100644
--- a/wqflask/wqflask/user_manager.py
+++ b/wqflask/wqflask/user_manager.py
@@ -30,7 +30,7 @@ Redis = redis.StrictRedis()
from flask import (Flask, g, render_template, url_for, request, make_response,
- redirect, flash)
+ redirect, flash, abort)
from wqflask import app
@@ -357,22 +357,28 @@ def login():
if valid:
- session_id_signed = successful_login(user)
- flash("Thank you for logging in {}.".format(user.full_name), "alert-success")
- response = make_response(redirect(url_for('index_page')))
- response.set_cookie(UserSession.cookie_name, session_id_signed)
+ return actual_login(user)
+
else:
unsuccessful_login(user)
flash("Invalid email-address or password. Please try again.", "alert-error")
response = make_response(redirect(url_for('login')))
- return response
+ return response
+def actual_login(user, assumed_by=None):
+ """The meat of the logging in process"""
+ session_id_signed = successful_login(user, assumed_by)
+ flash("Thank you for logging in {}.".format(user.full_name), "alert-success")
+ response = make_response(redirect(url_for('index_page')))
+ response.set_cookie(UserSession.cookie_name, session_id_signed)
+ return response
-def successful_login(user):
+def successful_login(user, assumed_by=None):
login_rec = model.Login(user)
login_rec.successful = True
login_rec.session_id = str(uuid.uuid4())
+ login_rec.assumed_by = assumed_by
#session_id = "session_id:{}".format(login_rec.session_id)
session_id_signature = actual_hmac_creation(login_rec.session_id)
session_id_signed = login_rec.session_id + ":" + session_id_signature
@@ -424,23 +430,61 @@ def forgot_password_submit():
return render_template("new_security/forgot_password_step2.html",
subject=ForgotPasswordEmail.subject)
+@app.errorhandler(401)
+def unauthorized(error):
+ return redirect(url_for('login'))
+
+def super_only():
+ try:
+ superuser = g.user_session.user_ob.superuser
+ except AttributeError:
+ superuser = False
+ if not superuser:
+ flash("You must be a superuser to access that page.", "alert-error")
+ abort(401)
+
@app.route("/manage/users")
def manage_users():
+ super_only()
template_vars = UsersManager()
return render_template("admin/user_manager.html", **template_vars.__dict__)
@app.route("/manage/user")
def manage_user():
+ super_only()
template_vars = UserManager(request.args)
return render_template("admin/ind_user_manager.html", **template_vars.__dict__)
@app.route("/manage/groups")
def manage_groups():
+ super_only()
template_vars = GroupsManager(request.args)
return render_template("admin/group_manager.html", **template_vars.__dict__)
+@app.route("/manage/make_superuser")
+def make_superuser():
+ super_only()
+ params = request.args
+ user_id = params['user_id']
+ user = model.User.query.get(user_id)
+ superuser_info = basic_info()
+ superuser_info['crowned_by'] = g.user_session.user_id
+ user.superuser = json.dumps(superuser_info, sort_keys=True)
+ db_session.commit()
+ flash("We've made {} a superuser!".format(user.name_and_org))
+ return redirect(url_for("manage_users"))
+
+@app.route("/manage/assume_identity")
+def assume_identity():
+ super_only()
+ params = request.args
+ user_id = params['user_id']
+ user = model.User.query.get(user_id)
+ assumed_by = g.user_session.user_id
+ return actual_login(user, assumed_by)
+
@app.route("/n/register", methods=('GET', 'POST'))
def register():