-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ajout d'une page de gestion des sessions
- Loading branch information
Showing
10 changed files
with
229 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
{% extends "member/settings/base.html" %} | ||
{% load i18n %} | ||
{% load date %} | ||
|
||
|
||
{% block title %} | ||
{% trans "Gestion des sessions" %} | ||
{% endblock %} | ||
|
||
|
||
|
||
{% block breadcrumb %} | ||
<li> | ||
{% trans "Gestion des sessions" %} | ||
</li> | ||
{% endblock %} | ||
|
||
|
||
|
||
{% block headline %} | ||
{% trans "Gestion des sessions" %} | ||
{% endblock %} | ||
|
||
|
||
|
||
{% block content %} | ||
{% include "misc/paginator.html" with position="top" %} | ||
|
||
{% if sessions %} | ||
<div class="table-wrapper"> | ||
<table class="fullwidth"> | ||
<thead> | ||
<th>{% trans "Session" %}</th> | ||
<th>{% trans "Appareil" %}</th> | ||
<th>{% trans "Adresse IP" %}</th> | ||
<th>{% trans "Géolocalisation" %}</th> | ||
<th>{% trans "Dernière utilisation" %}</th> | ||
<th>{% trans "Actions" %}</th> | ||
</thead> | ||
<tbody> | ||
{% for session in sessions %} | ||
<tr> | ||
{% if session.is_active %} | ||
<td><strong>{% trans "Session actuelle" %}</strong></td> | ||
{% else %} | ||
<td>{% trans "Autre session" %}</td> | ||
{% endif %} | ||
<td>{{ session.user_agent }}</td> | ||
<td>{{ session.ip_address }}</td> | ||
<td>{{ session.geolocalization }}</td> | ||
<td>{{ session.last_visit|humane_time }}</td> | ||
<td> | ||
<form method="post" action="{% url 'delete-session' %}"> | ||
{% csrf_token %} | ||
<input type="hidden" name="session_key" value="{{ session.session_key }}"> | ||
<button type="submit" class="btn btn-grey ico-after red cross" {% if session.is_active %}disabled{% endif %}> | ||
{% trans "Déconnecter" %} | ||
</button> | ||
</form> | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</div> | ||
{% else %} | ||
<em>{% trans "Aucune session ne correspond à votre compte." %}</em> | ||
{% endif %} | ||
|
||
{% include "misc/paginator.html" with position="bottom" %} | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from django.urls import reverse | ||
from django.test import TestCase | ||
|
||
from zds.member.tests.factories import ProfileFactory | ||
|
||
|
||
class SessionManagementTests(TestCase): | ||
def test_anonymous_cannot_access(self): | ||
self.client.logout() | ||
|
||
response = self.client.get(reverse("list-sessions")) | ||
self.assertRedirects(response, reverse("member-login") + "?next=" + reverse("list-sessions")) | ||
|
||
response = self.client.post(reverse("delete-session")) | ||
self.assertRedirects(response, reverse("member-login") + "?next=" + reverse("delete-session")) | ||
|
||
def test_user_can_access(self): | ||
profile = ProfileFactory() | ||
self.client.force_login(profile.user) | ||
|
||
response = self.client.get(reverse("list-sessions")) | ||
self.assertEqual(response.status_code, 200) | ||
|
||
session_key = self.client.session.session_key | ||
response = self.client.post(reverse("delete-session"), {"session_key": session_key}) | ||
self.assertRedirects(response, reverse("list-sessions")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
from importlib import import_module | ||
from user_agents import parse | ||
|
||
from django.conf import settings | ||
from django.contrib.auth.mixins import LoginRequiredMixin | ||
from django.contrib.sessions.models import Session | ||
from django.shortcuts import redirect | ||
from django.urls import reverse | ||
from django.utils.translation import gettext_lazy as _ | ||
from django.views.generic import View | ||
|
||
from zds.member.utils import get_geolocalization | ||
from zds.utils.paginator import ZdSPagingListView | ||
|
||
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore | ||
|
||
|
||
class ListSessions(LoginRequiredMixin, ZdSPagingListView): | ||
"""List the user's sessions.""" | ||
|
||
model = Session | ||
context_object_name = "sessions" | ||
template_name = "member/settings/sessions.html" | ||
paginate_by = 10 | ||
|
||
def get_context_data(self, **kwargs): | ||
self.object_list = [] | ||
for session in Session.objects.iterator(): | ||
data = session.get_decoded() | ||
if data.get("_auth_user_id") == str(self.request.user.pk): | ||
session_context = { | ||
"session_key": session.session_key, | ||
"user_agent": str(parse(data.get("user_agent", ""))), | ||
"ip_address": data.get("ip_address", ""), | ||
"geolocalization": get_geolocalization(data.get("ip_address", "")) or _("Inconnue"), | ||
"last_visit": data.get("last_visit", 0), | ||
"is_active": session.session_key == self.request.session.session_key, | ||
} | ||
|
||
if session_context["is_active"]: | ||
self.object_list.insert(0, session_context) | ||
else: | ||
self.object_list.append(session_context) | ||
|
||
return super().get_context_data(**kwargs) | ||
|
||
|
||
class DeleteSession(LoginRequiredMixin, View): | ||
"""Delete a user's session.""" | ||
|
||
def post(self, request, *args, **kwargs): | ||
session_key = request.POST.get("session_key", None) | ||
if session_key and session_key != self.request.session.session_key: | ||
session = SessionStore(session_key=session_key) | ||
if session.get("_auth_user_id", "") == str(self.request.user.pk): | ||
session.flush() | ||
|
||
return redirect(reverse("list-sessions")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from datetime import datetime | ||
|
||
from zds.member.views import get_client_ip | ||
|
||
|
||
class ManageSessionsMiddleware: | ||
def __init__(self, get_response): | ||
self.get_response = get_response | ||
|
||
def __call__(self, request): | ||
return self.process_response(request, self.get_response(request)) | ||
|
||
def process_response(self, request, response): | ||
try: | ||
user = request.user | ||
except AttributeError: | ||
user = None | ||
|
||
if user is not None and user.is_authenticated: | ||
session = request.session | ||
session["ip_address"] = get_client_ip(request) | ||
session["user_agent"] = request.META.get("HTTP_USER_AGENT", "") | ||
session["last_visit"] = datetime.now().timestamp() | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters