about summary refs log tree commit diff
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():