Add firmware upgrade groups and move custom routes
This commit is contained in:
parent
ddf72a1cd1
commit
a66b8c3422
179
authserver/authserver/api/customroutes.py
Normal file
179
authserver/authserver/api/customroutes.py
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import get_object_or_404, get_list_or_404
|
||||||
|
|
||||||
|
from rest_framework import mixins, permissions, status, viewsets
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from . import models, serializers, views
|
||||||
|
from authserver.settings import PROTOSPACE_LOGIN_PAGE, FIRMWARE_VERSION_MAGIC
|
||||||
|
|
||||||
|
LOG_DIRECTORY = '/var/log/pslockout'
|
||||||
|
VALID_TIME = 1000000000
|
||||||
|
|
||||||
|
EVENTS = [
|
||||||
|
'LOG_BOOT_UP - =========== Booted up, version: ',
|
||||||
|
'LOG_INIT_COMPLETE - Initialization completed',
|
||||||
|
'LOG_WIFI_CONNECTED - Wifi connected',
|
||||||
|
'LOG_WIFI_DISCONNECTED - Wifi disconnected',
|
||||||
|
'LOG_COMM_LOCK_ARM - Received arm request over web',
|
||||||
|
'LOG_COMM_LOCK_DISARM - Received disarm request over web',
|
||||||
|
'LOG_COMM_LOCK_FAIL - Lock status communication failed, code: ',
|
||||||
|
'LOG_COMM_CARD_FAIL - Card list communication failed, code: ',
|
||||||
|
'LOG_COMM_INFO_FAIL - Info log communication failed, code: ',
|
||||||
|
'LOG_LOCK_OFF - Lock turned off',
|
||||||
|
'LOG_LOCK_ARMED - Lock armed',
|
||||||
|
'LOG_LOCK_TIMEOUT - Lock arming timed out',
|
||||||
|
'LOG_LOCK_ON - Lock turned on',
|
||||||
|
'LOG_LOCK_DISARMED - Lock disarmed',
|
||||||
|
'LOG_LOCK_ERROR - Button held while arming lock',
|
||||||
|
'LOG_CARD_GOOD_READ - Successful read from card: ',
|
||||||
|
'LOG_CARD_ACCEPTED - Accepted card: ',
|
||||||
|
'LOG_CARD_DENIED - Denied card: ',
|
||||||
|
'LOG_UPDATE_FAILED - Firmware update failed, code: ',
|
||||||
|
]
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
def login(request):
|
||||||
|
username = request.data.get('username').lower()
|
||||||
|
password = request.data.get('password')
|
||||||
|
if username is None or password is None:
|
||||||
|
return Response({'error': 'Please provide both username and password'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
post_data = {'user_name': username, 'web_pw': password, 'SubmitButton': 'Login'}
|
||||||
|
res = requests.post(PROTOSPACE_LOGIN_PAGE, post_data, allow_redirects=False)
|
||||||
|
if res.status_code == requests.codes.ok:
|
||||||
|
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
lockout_username = username.replace('.', '')
|
||||||
|
|
||||||
|
user, created = User.objects.get_or_create(username=lockout_username)
|
||||||
|
user.set_password(password) # not validated
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
if created:
|
||||||
|
models.Profile.objects.create(user=user)
|
||||||
|
|
||||||
|
token, _ = Token.objects.get_or_create(user=user)
|
||||||
|
|
||||||
|
return Response({'token': token.key}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
def cards(request, mac):
|
||||||
|
tool = get_object_or_404(models.Tool, mac=mac)
|
||||||
|
cards = models.Card.objects.all().filter(profile__courses__tools=tool)
|
||||||
|
card_numbers = [card.number for card in cards]
|
||||||
|
|
||||||
|
return Response(','.join(card_numbers), status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@api_view(['PUT'])
|
||||||
|
@permission_classes((views.IsLockoutAdmin,))
|
||||||
|
def update_cards(request):
|
||||||
|
data = request.data
|
||||||
|
updated_count = 0
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return Response({'error': 'Please provide card data in the form username=cardnumber,cardnumber,cardnumber'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
for username, card_numbers in data.items():
|
||||||
|
try:
|
||||||
|
lockout_username = username.replace('.', '')
|
||||||
|
profile = models.Profile.objects.get(user__username=lockout_username)
|
||||||
|
except models.Profile.DoesNotExist:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for card_number in card_numbers.split(','):
|
||||||
|
card, _ = models.Card.objects.get_or_create(
|
||||||
|
profile=profile,
|
||||||
|
number=card_number
|
||||||
|
)
|
||||||
|
if card: updated_count += 1
|
||||||
|
|
||||||
|
return Response({'updated': updated_count}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
def infolog(request, mac):
|
||||||
|
entries_processed = 0
|
||||||
|
oldest_valid_log_time = time.time()
|
||||||
|
|
||||||
|
tool = get_object_or_404(models.Tool, mac=mac)
|
||||||
|
|
||||||
|
encoded_log = request.data.get('log')
|
||||||
|
if encoded_log:
|
||||||
|
decoded_log = base64.b64decode(encoded_log)
|
||||||
|
unpacked_log = list(struct.iter_unpack('<IB10s', decoded_log))
|
||||||
|
|
||||||
|
for entry in unpacked_log:
|
||||||
|
if entry[0] < oldest_valid_log_time and entry[0] > VALID_TIME:
|
||||||
|
oldest_valid_log_time = entry[0]
|
||||||
|
|
||||||
|
with open(LOG_DIRECTORY + '/devices/' + mac + '.log', 'a') as log_file:
|
||||||
|
for entry in unpacked_log:
|
||||||
|
# if time is obviously wrong, just use oldest valid log time or now
|
||||||
|
entry_time = entry[0] if entry[0] > VALID_TIME else oldest_valid_log_time
|
||||||
|
entry_time_string = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(entry_time))
|
||||||
|
|
||||||
|
entry_event = EVENTS[entry[1]]
|
||||||
|
entry_data = entry[2].decode('utf-8').strip('\0')
|
||||||
|
|
||||||
|
if entry_data:
|
||||||
|
user = models.User.objects.filter(profile__cards__number=entry_data)
|
||||||
|
if user.count():
|
||||||
|
entry_data += ' (' + str(user.first()) + ')'
|
||||||
|
|
||||||
|
entry_string = '{} - {} - {}{}'.format(entry_time_string, mac, entry_event, entry_data)
|
||||||
|
|
||||||
|
entries_processed += 1
|
||||||
|
log_file.write(entry_string + '\n')
|
||||||
|
|
||||||
|
version = str(get_object_or_404(models.Firmware, tools=tool))
|
||||||
|
version_string = '{} {} {}'.format(FIRMWARE_VERSION_MAGIC, version, FIRMWARE_VERSION_MAGIC)
|
||||||
|
|
||||||
|
response_object = {
|
||||||
|
'processed': entries_processed,
|
||||||
|
'unixTime': int(time.time()),
|
||||||
|
'version': version_string,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response(response_object, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
def update(request, mac):
|
||||||
|
tool = get_object_or_404(models.Tool, mac=mac)
|
||||||
|
firmware = get_object_or_404(models.Firmware, tools=tool)
|
||||||
|
|
||||||
|
response = HttpResponse(firmware.binary, content_type='text/plain')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename=firmware_{}.bin'.format(firmware.version)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@api_view(['PUT'])
|
||||||
|
@permission_classes((permissions.IsAuthenticated,))
|
||||||
|
def select_courses(request):
|
||||||
|
if 'courses' not in request.data:
|
||||||
|
return Response({'error': 'Please provide a list of course slugs'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
courses = request.data.get('courses')
|
||||||
|
|
||||||
|
profile = get_object_or_404(models.Profile, user=request.user)
|
||||||
|
|
||||||
|
if profile.courses.count() or profile.selected_courses:
|
||||||
|
return Response({'error': 'Already selected courses'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
if len(courses):
|
||||||
|
course_objects = get_list_or_404(models.Course, slug__in=courses)
|
||||||
|
profile.courses.set(course_objects)
|
||||||
|
profile.selected_courses = True
|
||||||
|
profile.save()
|
||||||
|
|
||||||
|
return Response({'updated': len(courses)}, status=status.HTTP_200_OK)
|
|
@ -6,14 +6,12 @@ class Category(models.Model):
|
||||||
slug = models.CharField(max_length=32, unique=True)
|
slug = models.CharField(max_length=32, unique=True)
|
||||||
info = models.TextField(max_length=1024, blank=True)
|
info = models.TextField(max_length=1024, blank=True)
|
||||||
photo = models.ImageField(blank=True)
|
photo = models.ImageField(blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Firmware(models.Model):
|
class Firmware(models.Model):
|
||||||
version = models.CharField(unique=True, max_length=4)
|
version = models.CharField(unique=True, max_length=4)
|
||||||
binary = models.FileField()
|
binary = models.FileField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.version
|
return self.version
|
||||||
|
|
||||||
|
@ -26,7 +24,7 @@ class Tool(models.Model):
|
||||||
photo = models.ImageField(blank=True)
|
photo = models.ImageField(blank=True)
|
||||||
mac = models.CharField(max_length=12)
|
mac = models.CharField(max_length=12)
|
||||||
firmware = models.ForeignKey(Firmware, blank=True, null=True, related_name='tools', on_delete=models.SET_NULL)
|
firmware = models.ForeignKey(Firmware, blank=True, null=True, related_name='tools', on_delete=models.SET_NULL)
|
||||||
|
upgrade_group = models.CharField(max_length=32)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -34,7 +32,6 @@ class Course(models.Model):
|
||||||
name = models.CharField(max_length=64)
|
name = models.CharField(max_length=64)
|
||||||
slug = models.CharField(max_length=32, unique=True)
|
slug = models.CharField(max_length=32, unique=True)
|
||||||
tools = models.ManyToManyField(Tool, blank=True)
|
tools = models.ManyToManyField(Tool, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -43,13 +40,11 @@ class Profile(models.Model):
|
||||||
lockout_admin = models.BooleanField(default=False)
|
lockout_admin = models.BooleanField(default=False)
|
||||||
courses = models.ManyToManyField(Course, blank=True)
|
courses = models.ManyToManyField(Course, blank=True)
|
||||||
selected_courses = models.BooleanField(default=False)
|
selected_courses = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.username
|
return self.user.username
|
||||||
|
|
||||||
class Card(models.Model):
|
class Card(models.Model):
|
||||||
profile = models.ForeignKey(Profile, related_name='cards', on_delete=models.CASCADE)
|
profile = models.ForeignKey(Profile, related_name='cards', on_delete=models.CASCADE)
|
||||||
number = models.CharField(max_length=10)
|
number = models.CharField(max_length=10)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.number
|
return self.number
|
||||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
from authserver.settings import FIRMWARE_VERSION_MAGIC
|
from authserver.settings import FIRMWARE_VERSION_MAGIC, UPGRADE_GROUPS
|
||||||
|
|
||||||
class CategorySerializer(serializers.HyperlinkedModelSerializer):
|
class CategorySerializer(serializers.HyperlinkedModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='category-detail', lookup_field='slug')
|
url = serializers.HyperlinkedIdentityField(view_name='category-detail', lookup_field='slug')
|
||||||
|
@ -37,6 +37,7 @@ class ToolSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
slug_field='version',
|
slug_field='version',
|
||||||
queryset=models.Firmware.objects.all().order_by('-version')
|
queryset=models.Firmware.objects.all().order_by('-version')
|
||||||
)
|
)
|
||||||
|
upgrade_group = serializers.ChoiceField(choices=UPGRADE_GROUPS)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Tool
|
model = models.Tool
|
||||||
|
@ -79,6 +80,7 @@ class FirmwareSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='firmware-detail', lookup_field='version')
|
url = serializers.HyperlinkedIdentityField(view_name='firmware-detail', lookup_field='version')
|
||||||
version = serializers.CharField(read_only=True)
|
version = serializers.CharField(read_only=True)
|
||||||
tools = serializers.StringRelatedField(read_only=True, many=True)
|
tools = serializers.StringRelatedField(read_only=True, many=True)
|
||||||
|
deploy_to_group = serializers.ChoiceField(write_only=True, choices=['None', 'All'] + UPGRADE_GROUPS)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Firmware
|
model = models.Firmware
|
||||||
|
@ -101,4 +103,18 @@ class FirmwareSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
raise serializers.ValidationError('Firmware version already exists.')
|
raise serializers.ValidationError('Firmware version already exists.')
|
||||||
|
|
||||||
validated_data['version'] = version
|
validated_data['version'] = version
|
||||||
return serializers.ModelSerializer.create(self, validated_data)
|
group = validated_data.pop('deploy_to_group')
|
||||||
|
firmware = serializers.ModelSerializer.create(self, validated_data)
|
||||||
|
|
||||||
|
if group == 'None':
|
||||||
|
tools = []
|
||||||
|
elif group == 'All':
|
||||||
|
tools = models.Tool.objects.all()
|
||||||
|
else:
|
||||||
|
tools = models.Tool.objects.filter(upgrade_group=group)
|
||||||
|
|
||||||
|
for tool in tools:
|
||||||
|
tool.firmware = firmware
|
||||||
|
tool.save()
|
||||||
|
|
||||||
|
return firmware
|
||||||
|
|
|
@ -16,9 +16,6 @@ from rest_framework.response import Response
|
||||||
from . import models, serializers
|
from . import models, serializers
|
||||||
from authserver.settings import PROTOSPACE_LOGIN_PAGE, FIRMWARE_VERSION_MAGIC
|
from authserver.settings import PROTOSPACE_LOGIN_PAGE, FIRMWARE_VERSION_MAGIC
|
||||||
|
|
||||||
LOG_DIRECTORY = '/var/log/pslockout'
|
|
||||||
VALID_TIME = 1000000000
|
|
||||||
|
|
||||||
class IsLockoutAdmin(permissions.BasePermission):
|
class IsLockoutAdmin(permissions.BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
try:
|
try:
|
||||||
|
@ -74,162 +71,3 @@ class FirmwareViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = (IsLockoutAdmin,)
|
permission_classes = (IsLockoutAdmin,)
|
||||||
lookup_field='version'
|
lookup_field='version'
|
||||||
http_method_names = ['get', 'post', 'head', 'delete', 'options']
|
http_method_names = ['get', 'post', 'head', 'delete', 'options']
|
||||||
|
|
||||||
@api_view(['POST'])
|
|
||||||
def login(request):
|
|
||||||
username = request.data.get('username').lower()
|
|
||||||
password = request.data.get('password')
|
|
||||||
if username is None or password is None:
|
|
||||||
return Response({'error': 'Please provide both username and password'},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
post_data = {'user_name': username, 'web_pw': password, 'SubmitButton': 'Login'}
|
|
||||||
res = requests.post(PROTOSPACE_LOGIN_PAGE, post_data, allow_redirects=False)
|
|
||||||
if res.status_code == requests.codes.ok:
|
|
||||||
return Response({'error': 'Invalid Credentials'}, status=status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
||||||
lockout_username = username.replace('.', '')
|
|
||||||
|
|
||||||
user, created = User.objects.get_or_create(username=lockout_username)
|
|
||||||
user.set_password(password) # not validated
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
if created:
|
|
||||||
models.Profile.objects.create(user=user)
|
|
||||||
|
|
||||||
token, _ = Token.objects.get_or_create(user=user)
|
|
||||||
|
|
||||||
return Response({'token': token.key}, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
|
||||||
def cards(request, mac):
|
|
||||||
tool = get_object_or_404(models.Tool, mac=mac)
|
|
||||||
cards = models.Card.objects.all().filter(profile__courses__tools=tool)
|
|
||||||
card_numbers = [card.number for card in cards]
|
|
||||||
|
|
||||||
return Response(','.join(card_numbers), status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
@api_view(['PUT'])
|
|
||||||
@permission_classes((IsLockoutAdmin,))
|
|
||||||
def update_cards(request):
|
|
||||||
data = request.data
|
|
||||||
updated_count = 0
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
return Response({'error': 'Please provide card data in the form username=cardnumber,cardnumber,cardnumber'},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
for username, card_numbers in data.items():
|
|
||||||
try:
|
|
||||||
lockout_username = username.replace('.', '')
|
|
||||||
profile = models.Profile.objects.get(user__username=lockout_username)
|
|
||||||
except models.Profile.DoesNotExist:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for card_number in card_numbers.split(','):
|
|
||||||
card, _ = models.Card.objects.get_or_create(
|
|
||||||
profile=profile,
|
|
||||||
number=card_number
|
|
||||||
)
|
|
||||||
if card: updated_count += 1
|
|
||||||
|
|
||||||
return Response({'updated': updated_count}, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
EVENTS = [
|
|
||||||
'LOG_BOOT_UP - =========== Booted up, version: ',
|
|
||||||
'LOG_INIT_COMPLETE - Initialization completed',
|
|
||||||
'LOG_WIFI_CONNECTED - Wifi connected',
|
|
||||||
'LOG_WIFI_DISCONNECTED - Wifi disconnected',
|
|
||||||
'LOG_COMM_LOCK_ARM - Received arm request over web',
|
|
||||||
'LOG_COMM_LOCK_DISARM - Received disarm request over web',
|
|
||||||
'LOG_COMM_LOCK_FAIL - Lock status communication failed, code: ',
|
|
||||||
'LOG_COMM_CARD_FAIL - Card list communication failed, code: ',
|
|
||||||
'LOG_COMM_INFO_FAIL - Info log communication failed, code: ',
|
|
||||||
'LOG_LOCK_OFF - Lock turned off',
|
|
||||||
'LOG_LOCK_ARMED - Lock armed',
|
|
||||||
'LOG_LOCK_TIMEOUT - Lock arming timed out',
|
|
||||||
'LOG_LOCK_ON - Lock turned on',
|
|
||||||
'LOG_LOCK_DISARMED - Lock disarmed',
|
|
||||||
'LOG_LOCK_ERROR - Button held while arming lock',
|
|
||||||
'LOG_CARD_GOOD_READ - Successful read from card: ',
|
|
||||||
'LOG_CARD_ACCEPTED - Accepted card: ',
|
|
||||||
'LOG_CARD_DENIED - Denied card: ',
|
|
||||||
'LOG_UPDATE_FAILED - Firmware update failed, code: ',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
|
||||||
def infolog(request, mac):
|
|
||||||
entries_processed = 0
|
|
||||||
oldest_valid_log_time = time.time()
|
|
||||||
|
|
||||||
tool = get_object_or_404(models.Tool, mac=mac)
|
|
||||||
|
|
||||||
encoded_log = request.data.get('log')
|
|
||||||
if encoded_log:
|
|
||||||
decoded_log = base64.b64decode(encoded_log)
|
|
||||||
unpacked_log = list(struct.iter_unpack('<IB10s', decoded_log))
|
|
||||||
|
|
||||||
for entry in unpacked_log:
|
|
||||||
if entry[0] < oldest_valid_log_time and entry[0] > VALID_TIME:
|
|
||||||
oldest_valid_log_time = entry[0]
|
|
||||||
|
|
||||||
with open(LOG_DIRECTORY + '/devices/' + mac + '.log', 'a') as log_file:
|
|
||||||
for entry in unpacked_log:
|
|
||||||
# if time is obviously wrong, just use oldest valid log time or now
|
|
||||||
entry_time = entry[0] if entry[0] > VALID_TIME else oldest_valid_log_time
|
|
||||||
entry_time_string = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(entry_time))
|
|
||||||
|
|
||||||
entry_event = EVENTS[entry[1]]
|
|
||||||
entry_data = entry[2].decode('utf-8').strip('\0')
|
|
||||||
|
|
||||||
if entry_data:
|
|
||||||
user = models.User.objects.filter(profile__cards__number=entry_data)
|
|
||||||
if user.count():
|
|
||||||
entry_data += ' (' + str(user.first()) + ')'
|
|
||||||
|
|
||||||
entry_string = '{} - {} - {}{}'.format(entry_time_string, mac, entry_event, entry_data)
|
|
||||||
|
|
||||||
entries_processed += 1
|
|
||||||
log_file.write(entry_string + '\n')
|
|
||||||
|
|
||||||
version = str(get_object_or_404(models.Firmware, tools=tool))
|
|
||||||
version_string = '{} {} {}'.format(FIRMWARE_VERSION_MAGIC, version, FIRMWARE_VERSION_MAGIC)
|
|
||||||
|
|
||||||
response_object = {
|
|
||||||
'processed': entries_processed,
|
|
||||||
'unixTime': int(time.time()),
|
|
||||||
'version': version_string,
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response(response_object, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
|
||||||
def update(request, mac):
|
|
||||||
tool = get_object_or_404(models.Tool, mac=mac)
|
|
||||||
firmware = get_object_or_404(models.Firmware, tools=tool)
|
|
||||||
|
|
||||||
response = HttpResponse(firmware.binary, content_type='text/plain')
|
|
||||||
response['Content-Disposition'] = 'attachment; filename=firmware_{}.bin'.format(firmware.version)
|
|
||||||
return response
|
|
||||||
|
|
||||||
@api_view(['PUT'])
|
|
||||||
@permission_classes((permissions.IsAuthenticated,))
|
|
||||||
def select_courses(request):
|
|
||||||
courses = request.data.get('courses')
|
|
||||||
if courses is None:
|
|
||||||
return Response({'error': 'Please provide a list of course slugs'},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
profile = get_object_or_404(models.Profile, user=request.user)
|
|
||||||
|
|
||||||
if profile.courses.count() or profile.selected_courses:
|
|
||||||
return Response({'error': 'Please provide a list of course slugs'},
|
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
course_objects = get_list_or_404(models.Course, slug__in=courses)
|
|
||||||
profile.courses.set(course_objects)
|
|
||||||
profile.selected_courses = True
|
|
||||||
profile.save()
|
|
||||||
|
|
||||||
return Response({'updated': len(courses)}, status=status.HTTP_200_OK)
|
|
||||||
|
|
|
@ -130,3 +130,5 @@ MEDIA_URL = '/media/'
|
||||||
PROTOSPACE_LOGIN_PAGE = 'https://my.protospace.ca/login'
|
PROTOSPACE_LOGIN_PAGE = 'https://my.protospace.ca/login'
|
||||||
|
|
||||||
FIRMWARE_VERSION_MAGIC = 'MRWIZARD'
|
FIRMWARE_VERSION_MAGIC = 'MRWIZARD'
|
||||||
|
|
||||||
|
UPGRADE_GROUPS = ['Critical', 'Testing', 'Development']
|
||||||
|
|
|
@ -20,7 +20,7 @@ from django.urls import path
|
||||||
|
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
from .api import views
|
from .api import views, customroutes
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'tool', views.ToolViewSet)
|
router.register(r'tool', views.ToolViewSet)
|
||||||
|
@ -35,12 +35,12 @@ urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', admin.site.urls),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
url(r'^login/', views.login),
|
url(r'^login/', customroutes.login),
|
||||||
url(r'^cards/(?P<mac>.*)/', views.cards),
|
url(r'^cards/(?P<mac>.*)/', customroutes.cards),
|
||||||
url(r'^update-cards/', views.update_cards),
|
url(r'^update-cards/', customroutes.update_cards),
|
||||||
url(r'^infolog/(?P<mac>.*)/', views.infolog),
|
url(r'^infolog/(?P<mac>.*)/', customroutes.infolog),
|
||||||
url(r'^update/(?P<mac>.*)/', views.update),
|
url(r'^update/(?P<mac>.*)/', customroutes.update),
|
||||||
url(r'^select-courses/', views.select_courses),
|
url(r'^select-courses/', customroutes.select_courses),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG is True:
|
if settings.DEBUG is True:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user