Skip to content

Commit

Permalink
User Management GUI improvements & API additions
Browse files Browse the repository at this point in the history
For the incoming initial release (#3) :
* Improved the graphical "add user" feature for easier and more
efficient user registration.
* Integration of Trinity's Device Management view on the main admin panel.
* Added the new red/green logos on the "connected" page.
  • Loading branch information
darkgallium committed Dec 3, 2018
1 parent de01898 commit 9257d21
Show file tree
Hide file tree
Showing 16 changed files with 489 additions and 261 deletions.
6 changes: 3 additions & 3 deletions langate/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class DeviceSerializer(serializers.ModelSerializer):

class Meta:
model = Device
fields = ["id", "ip", "area", "name"]
read_only_fields = ["id", "ip", "area"]
fields = ["id", "ip", "mac", "area", "name"]
read_only_fields = ["id", "ip", "mac", "area"]


class ProfileSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -64,4 +64,4 @@ def update(self, instance, validated_data):

class Meta:
model = User
fields = ('id', 'username', 'email', 'is_staff', 'is_active', 'profile')
fields = ('id', 'first_name', 'last_name', 'username', 'email', 'is_staff', 'is_active', 'profile')
7 changes: 4 additions & 3 deletions langate/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from .views import *

urlpatterns = [
path('user_devices/', UserDeviceList.as_view()),
path('user_devices/<int:ident>/', UserDevice.as_view()),
path('devices_list/<int:pk>', DeviceList.as_view()),
path('device_details/<int:ident>/', DeviceDetails.as_view()),
path('device_status/<int:ident>/', DeviceStatus.as_view()),
path('user_list/', UserList.as_view()),
path('user_details/<int:pk>', UserDetails.as_view()),
path('user_password/<int:ident>', UserPasswordGenerator.as_view())
path('user_password/<int:pk>', UserPasswordGenerator.as_view())
]
52 changes: 41 additions & 11 deletions langate/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from portal.models import Device
from django.contrib.auth.models import User

from rest_framework.exceptions import APIException
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions
Expand All @@ -15,16 +16,27 @@
# Create your views here.


class UserDeviceList(APIView):
class DeviceList(APIView):
permission_classes = (permissions.IsAuthenticated,)

def get(self, request):
qs = Device.objects.filter(user=request.user)
serializer = DeviceSerializer(qs, many=True)
return Response(serializer.data)
def get(self, request, pk):
u = User.objects.get(id=pk)

if u == request.user or request.user.is_staff:
# A normal user should only have access to the list of its devices,
# So, we check that the request user matches the ID passed in parameter.
# Admin users have the right to consult anyone's list of devices.

qs = Device.objects.filter(user=u)
serializer = DeviceSerializer(qs, many=True)

class UserDevice(APIView):
return Response(serializer.data)

else:
raise PermissionDenied


class DeviceDetails(APIView):
permission_classes = (permissions.IsAuthenticated,)

def get_device(self, ident, user):
Expand All @@ -33,7 +45,7 @@ def get_device(self, ident, user):
dev = Device.objects.get(id=ident)

# If the API call is made by the device owner or an admin, we should proceed, otherwise we should abort
if (dev.user == user) or user.is_staff():
if (dev.user == user) or user.is_staff:
return dev
else:
raise PermissionDenied
Expand All @@ -56,10 +68,27 @@ def put(self, request, ident, format=None):

def delete(self, request, ident, format=None):

# Deleting the device you are currently on is not allowed via the API.
# Instead the user can log out from the portal.

client_ip = request.META.get('REMOTE_ADDR')
dev = self.get_device(ident, request.user)
dev.delete()

return Response(status=status.HTTP_204_NO_CONTENT)
if dev.ip == client_ip:
raise APIException("Deleting your current device is not allowed via the API.")

else:
dev.delete()
return Response(status=status.HTTP_204_NO_CONTENT)


class DeviceStatus(APIView):
permission_classes = (permissions.IsAdminUser,)

def get(self, request, ident):
up = random.randint(0, 100)
down = random.randint(0, 100)
return Response({"status": "up", "upload": up, "download": down})


class UserList(generics.ListCreateAPIView):
Expand All @@ -79,13 +108,14 @@ class UserDetails(generics.RetrieveUpdateDestroyAPIView):
class UserPasswordGenerator(APIView):
permission_classes = (permissions.IsAdminUser,)

def get(self, request, ident):
def get(self, request, pk):

# FIXME: This can raise User.DoesNotExist exception, not sure whether we should catch this...
user = User.objects.get(id=ident)
user = User.objects.get(id=pk)
p = random.randint(1000, 9999)

user.set_password(p)
user.save()

return Response({"password": p})

25 changes: 17 additions & 8 deletions langate/portal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,14 @@ class Device(models.Model):
ip = models.CharField(max_length=15)

# MAC address of the device
mac = models.CharField(max_length=17, unique=True)
mac = models.CharField(max_length=17)

# Area of the device, i.e. LAN or WiFi
area = models.CharField(max_length=4, default="LAN")

def create(self, validated_data, **kwargs):
# On creating a new device, we need to use the networking module to retrieve
# some information : for example the MAC address or the area of the device based on the IP.
def create(self, **validated_data):

mac = "ff:ff:ff:ff:ff:ff" # FIXME: replace with a call to the networking module : network.get_mac(ip)
area = "LAN" # FIXME: replace with a call to the networking module

return Device(mac=mac, area=area, **validated_data)
return Device(**validated_data)

# FIXME : we should consider also the case when an user deletes its last device !

Expand All @@ -77,3 +72,17 @@ def create_user_profile(sender, instance, created, **kwargs):
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()


@receiver(post_save, sender=Device)
def create_device(sender, instance, created, **kwargs):
# On creating a new device, we need to use the networking module to retrieve
# some information : for example the MAC address or the area of the device based on the IP.

if created:
instance.mac = "ff:ff:ff:ff:ff:ff" # FIXME: replace with a call to the networking module : network.get_mac(ip)
instance.area = "LAN" # FIXME: replace with a call to the networking module

instance.save()

# FIXME: we should check if the mac address of the device already exists in the db
19 changes: 12 additions & 7 deletions langate/portal/templates/portal/connected.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{% extends 'portal/portal_layout.html' %}
{% load static %}

{% block main %}

{% csrf_token %} <!-- Token needed for AJAX calls -->

{% if too_many_devices %}

<div class="text-white text-center pt-5">
<img src="{% static "logo_red.png" %}" class="logo-connected pt-3 mx-auto d-block animated slow pulse" />

<div class="text-white text-center pt-4">
<h2>Attention !</h2>
<p class="pt-1"><b>Vous êtes connecté sur plus de 3 appareils sur le réseau.</b></p>
<p>Vous devez déconnecter au moins un appareil du réseau avant de pouvoir accéder à internet sur cet appareil.</p>
Expand All @@ -31,8 +34,10 @@ <h2>Attention !</h2>

{% else %}

<div class="text-white text-center pt-5">
<h2>Bon jeu, {{ user.username }}</h2>
<img src="{% static "logo_green.png" %}" class="logo-connected pt-3 mx-auto d-block animated slow pulse" />

<div class="text-white text-center pt-4">
<h2>Bon jeu, {{ user.username }} !</h2>
<p class="pt-2">Vous êtes désormais connecté au réseau de l'InsaLan.</p>
</div>

Expand Down Expand Up @@ -113,7 +118,7 @@ <h5 class="modal-title">Modifier un appareil</h5>
id = $(this).data("deviceid");
$("#delete-device-confirm-btn").data("deviceid", id);

$.getJSON( "/api/user_devices/"+id, function( data ) {
$.getJSON( "/api/device_details/"+id, function( data ) {
$("#delete-device-name").text(data["name"]);
$("#delete-device-modal").modal("show");
});
Expand All @@ -132,7 +137,7 @@ <h5 class="modal-title">Modifier un appareil</h5>

$("#device-table").empty();

$.getJSON( "/api/user_devices/", function( data ) {
$.getJSON( "/api/devices_list/{{ user.id }}", function( data ) {
i = 1;

$.each(data, function (k, dev) {
Expand Down Expand Up @@ -173,7 +178,7 @@ <h5 class="modal-title">Modifier un appareil</h5>
let id = $(this).data("deviceid");

$.ajax({
url: '/api/user_devices/'+id+'/',
url: '/api/device_details/'+id+'/',
type: 'DELETE',

success: function(result) {
Expand Down Expand Up @@ -201,7 +206,7 @@ <h5 class="modal-title">Modifier un appareil</h5>
let id = $(this).data("deviceid");

$.ajax({
url: '/api/user_devices/'+id+'/',
url: '/api/device_details/'+id+'/',
type: 'PUT',
data: "name="+encodeURI($("#modify-device-name").val()),

Expand Down
Loading

0 comments on commit 9257d21

Please sign in to comment.