]> git.ipfire.org Git - pbs.git/commitdiff
Add a page on which admins can see all active sessions.
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 9 Dec 2012 11:33:40 +0000 (12:33 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 9 Dec 2012 11:33:40 +0000 (12:33 +0100)
backend/main.py
backend/managers.py
backend/sessions.py
backend/users.py
data/templates/base.html
data/templates/sessions/index.html [new file with mode: 0644]
web/__init__.py
web/handlers.py
web/handlers_auth.py
web/handlers_base.py
web/handlers_users.py

index e7aaf41a63ff56120300ea17abbd340b484e097c..be24867d3832b56894ede0d5e08f31c5e7c39b8f 100644 (file)
@@ -19,6 +19,7 @@ import mirrors
 import packages
 import repository
 import settings
+import sessions
 import sources
 import updates
 import uploads
@@ -50,6 +51,7 @@ class Pakfire(object):
                self.mirrors     = mirrors.Mirrors(self)
                self.packages    = packages.Packages(self)
                self.repos       = repository.Repositories(self)
+               self.sessions    = sessions.Sessions(self)
                self.sources     = sources.Sources(self)
                self.updates     = updates.Updates(self)
                self.uploads     = uploads.Uploads(self)
index 79f891895a903897167f8c1bf38173dbee0f8632..eeeb6829e22396bb47b1f9c33979d66932005c27 100644 (file)
@@ -922,3 +922,19 @@ class DeleteManager(Manager):
 
 
 managers.append(DeleteManager)
+
+class SessionsManager(Manager):
+       """
+               Cleans up sessions that are not valid anymore.
+               Keeps the database smaller.
+       """
+
+       @property
+       def timeout(self):
+               return 3600
+
+       def do(self):
+               self.pakfire.sessions.cleanup()
+
+
+managers.append(SessionsManager)
index 7c8260c3e36a363137b7e0e4aaf924c041663cee..73d7730e3266f3867f8f9c4043dcb219746c2afc 100644 (file)
@@ -14,6 +14,21 @@ class Sessions(base.Object):
 
                return session
 
+       def get_all(self):
+               query = "SELECT session_id FROM sessions WHERE valid_until >= NOW() \
+                       ORDER BY valid_until DESC"
+
+               sessions = []
+               for s in self.db.query(query):
+                       s = Session(self.pakfire, s.session_id)
+                       sessions.append(s)
+
+               return sessions
+
+       def cleanup(self):
+               # Delete all sessions that are not valid any more.
+               self.db.execute("DELETE FROM sessions WHERE valid_until < NOW()")
+
 
 class Session(base.Object):
        def __init__(self, pakfire, session_id):
@@ -32,9 +47,6 @@ class Session(base.Object):
                self._user = None
                self._impersonated_user = None
 
-               # Update the valid time of the session.
-               #self.update()
-
        @staticmethod
        def has_session(pakfire, session_id):
                if self.db.get("SELECT session_id FROM sessions WHERE session_id = %s \
@@ -43,25 +55,34 @@ class Session(base.Object):
 
                return False
 
-       def refresh(self):
-               self.db.execute("UPDATE sessions SET valid_until = DATE_ADD(NOW(), INTERVAL 3 DAY) \
-                       WHERE session_id = %s", self.id)
+       def refresh(self, address=None):
+               self.db.execute("UPDATE sessions \
+                       SET valid_until = DATE_ADD(NOW(), INTERVAL 3 DAY), from_address = %s \
+                       WHERE session_id = %s", address, self.id)
 
        def destroy(self):
                self.db.execute("DELETE FROM sessions WHERE session_id = %s", self.id)
 
-       @staticmethod
-       def cleanup(pakfire):
-               # Remove all sessions that are no more valid.
-               pakfire.db.execute("DELETE FROM sessions WHERE valid_until < NOW()")
-
        @property
        def user(self):
                if self._user is None:
                        self._user = users.User(self.pakfire, self.data.user_id)
+                       self._user.session = self
 
                return self._user
 
+       @property
+       def creation_time(self):
+               return self.data.creation_time
+
+       @property
+       def valid_until(self):
+               return self.data.valid_until
+
+       @property
+       def from_address(self):
+               return self.data.from_address
+
        @property
        def impersonated_user(self):
                if not self.data.impersonated_user_id:
@@ -70,6 +91,7 @@ class Session(base.Object):
                if self._impersonated_user is None:
                        self._impersonated_user = \
                                users.User(self.pakfire, self.data.impersonated_user_id)
+                       self._impersonated_user.session = self
 
                return self._impersonated_user
 
index 01a29b4d7da92f61bbfd7ec715e84efc2b8ddd44..8a32f11c296cb2611aeb2f8399cd4e9fb39006c3 100644 (file)
@@ -220,11 +220,20 @@ class User(base.Object):
                base.Object.__init__(self, pakfire)
                self.id = id
 
+               # A valid session of the user.
+               self.session = None
+
                # Cache.
                self._data = None
                self._emails = None
                self._perms = None
 
+       def __repr__(self):
+               return "<%s %s>" % (self.__class__.__name__, self.realname)
+
+       def __hash__(self):
+               return hash(self.id)
+
        def __cmp__(self, other):
                if other is None:
                        return 1
index ac7e85aede407319b7c655c3ca47d141110fe438..b164168ee5245b2f3946224fcb983f447412815b 100644 (file)
@@ -82,7 +82,7 @@
                                                                        {% if current_user %}
                                                                                <li>
                                                                                        <a href="/users">
-                                                                                               <i class="icon-user"></i>
+                                                                                               <i class="icon-group"></i>
                                                                                                {{ _("Users") }}
                                                                                        </a>
                                                                                </li>
                                                                                <li class="nav-header">
                                                                                        {{ _("Administration") }}
                                                                                </li>
+                                                                               <li>
+                                                                                       <a href="/sessions">
+                                                                                               <i class="icon-user"></i>
+                                                                                               {{ _("Sessions") }}
+                                                                                       </a>
+                                                                               </li>
                                                                                <li>
                                                                                        <a href="/uploads">
                                                                                                <i class="icon-upload"></i>
diff --git a/data/templates/sessions/index.html b/data/templates/sessions/index.html
new file mode 100644 (file)
index 0000000..ec388ec
--- /dev/null
@@ -0,0 +1,61 @@
+{% extends "../base.html" %}
+
+{% block title %}{{ _("Sessions") }}{% end block %}
+
+{% block body %}
+       <ul class="breadcrumb">
+               <li>
+                       <a href="/">{{ _("Home") }}</a>
+                       <span class="divider">/</span>
+               </li>
+               <li class="active">
+                       <a href="/sessions">{{ _("Sessions") }}</a>
+               </li>
+       </ul>
+
+       <div class="page-header">
+               <h2>{{ _("Sessions") }}</h2>
+       </div>
+
+       <table class="table table-striped table-hover">
+               <tbody>
+                       {% for user, user_sessions in sessions %}
+                               <tr>
+                                       <td>
+                                               <div class="ac">
+                                                       <img class="img-polaroid" src="{{ user.gravatar_icon(96) }}" alt="{{ user.realname }}">
+                                                       <br><br>
+                                                       <a href="/user/{{ user.name }}">{{ user.realname }}</a>
+                                               </div>
+                                       </td>
+                                       <td>
+                                               <table class="table table-striped table-hover">
+                                                       <thead>
+                                                               <tr>
+                                                                       <th>{{ _("Started") }}</th>
+                                                                       <th>{{ _("Valid until") }}</th>
+                                                                       <th>{{ _("Last seen at") }}</th>
+                                                               </tr>
+                                                       </thead>
+                                                       <tbody>
+                                                               {% for s in user_sessions %}
+                                                                       <tr>
+                                                                               <td>
+                                                                                       {{ format_date(s.creation_time) }}
+                                                                               </td>
+                                                                               <td>
+                                                                                       {{ format_date(s.valid_until) }}
+                                                                               </td>
+                                                                               <td>
+                                                                                       {{ s.from_address or _("N/A") }}
+                                                                               </td>
+                                                                       </tr>
+                                                               {% end %}
+                                                       </tbody>
+                                               </table>
+                                       </td>
+                               </tr>
+                       {% end %}
+               </tbody>
+       </table>
+{% end block %}
index 627dd8eafd5533c061b273572496e65075cc3c88..d8aa31a63094e31221740ac65e4f491384023e8f 100644 (file)
@@ -226,6 +226,9 @@ class Application(tornado.web.Application):
                        # Log
                        (r"/log", LogHandler),
 
+                       # Sessions
+                       (r"/sessions", SessionsHandler),
+
                ] + static_handlers + [
 
                        # Everything else is catched by the 404 handler.
index 638a0f3e0e22f6d6b7bdd019ebc17b2ceff48568..d10fe2e95d3d0170404ab583f754b29af7a8f698 100644 (file)
@@ -106,6 +106,30 @@ class LogHandler(BaseHandler):
                self.render("log.html", log=self.pakfire.log)
 
 
+class SessionsHandler(BaseHandler):
+       def prepare(self):
+               # This is only accessible for administrators.
+               if not self.current_user.is_admin():
+                       raise tornado.web.HTTPError(403)
+
+       @tornado.web.authenticated
+       def get(self):
+               sessions = self.pakfire.sessions.get_all()
+
+               # Sort the sessions by user.
+               users = {}
+
+               for s in sessions:
+                       try:
+                               users[s.user].append(s)
+                       except KeyError:
+                               users[s.user] = [s]
+
+               sessions = sorted(users.items())
+
+               self.render("sessions/index.html", sessions=sessions)
+
+
 class RepositoryDetailHandler(BaseHandler):
        def get(self, distro, repo):
                distro = self.pakfire.distros.get_by_name(distro)
index 541311bdfd2cf282b6c257dc7afd4441652b4b21..822da85cc1e1dc5a94c4935828040e2e406ed188 100644 (file)
@@ -28,7 +28,7 @@ class LoginHandler(BaseHandler):
                        session = backend.sessions.Session.create(self.pakfire, user)
 
                        # Set a cookie and update the current user.
-                       self.set_cookie("session_id", session.id)
+                       self.set_cookie("session_id", session.id, expires=session.valid_until)
                        self._current_user = user
 
                        # If there is "next" given, we redirect the user accordingly.
@@ -117,7 +117,7 @@ class ActivationHandler(BaseHandler):
                                session = backend.sessions.Session.create(self.pakfire, user)
 
                                # Set a cookie and update the current user.
-                               self.set_cookie("session_id", session.id)
+                               self.set_cookie("session_id", session.id, expires=session.valid_until)
                                self._current_user = user
 
                        self.render("register-activation-success.html", user=user)
index 9b8c5ae44081bce64670d2898bb6de431ea998b6..b2d7f768d6f9785d8afe687aa7f2e71d88deda1d 100644 (file)
@@ -12,7 +12,6 @@ import traceback
 
 import backend
 import backend.misc
-import backend.sessions
 
 class BaseHandler(tornado.web.RequestHandler):
        @property
@@ -24,21 +23,23 @@ class BaseHandler(tornado.web.RequestHandler):
                if not session_id:
                        return
 
-               try:
-                       self.session = backend.sessions.Session(self.pakfire, session_id)
-               except:
+               # Get the session from the database.
+               session = self.pakfire.sessions.get(session_id)
+
+               # Return nothing, if no session was found.
+               if not session:
                        return
 
                # Update the session lifetime.
-               # XXX refresh cookie, too
-               self.session.refresh()
+               session.refresh(self.request.remote_ip)
+               self.set_cookie("session_id", session.id, expires=session.valid_until)
 
                # If the session impersonated a user, we return that one.
-               if self.session.impersonated_user:
-                       return self.session.impersonated_user
+               if session.impersonated_user:
+                       return session.impersonated_user
 
                # By default, we return the user of this session.
-               return self.session.user
+               return session.user
 
        def get_user_locale(self):
                DEFAULT_LOCALE = tornado.locale.get("en_US")
@@ -93,6 +94,10 @@ class BaseHandler(tornado.web.RequestHandler):
 
        @property
        def render_args(self):
+               session = None
+               if self.current_user:
+                       session = self.current_user.session
+
                ret = {
                        "bugtracker"      : self.pakfire.bugzilla,
                        "hostname"        : self.request.host,
@@ -103,12 +108,10 @@ class BaseHandler(tornado.web.RequestHandler):
                        "format_filemode" : backend.misc.format_filemode,
                        "lang"            : self.locale.code[:2],
                        "pakfire_version" : pakfire.__version__,
+                       "session"         : session,
                        "year"            : time.strftime("%Y"),
                }
 
-               # Add session.
-               ret["session"] = getattr(self, "session", None)
-
                return ret
 
        def render(self, *args, **kwargs):
index a98c6cb44919c894debc20d9af4b3f70cb42b75e..7c1f131e22c2e1bb12b5019fa151f9f6f2a5354b 100644 (file)
@@ -29,7 +29,8 @@ class UserImpersonateHandler(BaseHandler):
                action = self.get_argument("action", "start")
 
                if action == "stop":
-                       self.session.stop_impersonation()
+                       if self.current_user.session:
+                               self.current_user.session.stop_impersonation()
                        self.redirect("/")
                        return
 
@@ -55,7 +56,8 @@ class UserImpersonateHandler(BaseHandler):
                if not user:
                        raise tornado.web.HTTPError(404, "User does not exist: %s" % username)
 
-               self.session.start_impersonation(user)
+               if self.current_user.session:
+                       self.current_user.session.start_impersonation(user)
 
                # Redirect to start page.
                self.redirect("/")