Commit 0b73aa6c authored by Hubert Denkmair's avatar Hubert Denkmair
Browse files

improve API

parent 1c5f0843
......@@ -18,5 +18,5 @@ urlpatterns = [
path('snake/', include('ide.urls')),
path('highscore/', include('highscore.urls')),
path('docs/', include('docs.urls')),
path('api/', include('api.urls')),
path('api/v1/', include('api.urls')),
]
{% extends 'core/base.html' %}
{% load static %}
{% block css %}
<style>
table.api_keys td {
padding: 0 1em;
}
table.api_keys td, table.api_keys th
{
background-color:rgba(0,0,0,0.2);
}
table.api_keys input {
width:100%;
}
table.api_keys button {
border: 2px solid #321700;
background-color: #613600;
color:white;
padding:5px;
}
</style>
{% endblock %}
{% block content %}
<h1>API Keys</h1>
<table>
<table class="api_keys">
<thead>
<tr>
<th>API Key</th>
......@@ -13,25 +37,24 @@
</thead>
<tbody>
{% for key in user.apikey_set.all %}
<form action="{% url "api_key_delete" key_id=key.id %}" method="post">
{% csrf_token %}
<tr>
<td>{{ key.key }}</td>
<td>{{ key.comment }}</td>
<td>
<form action="{% url "api_key_delete" key_id=key.id %}" method="post">
{% csrf_token %}
<td><button type="submit">Revoke</button></td>
</form>
</td>
<td><button type="submit">Revoke</button></td>
</tr>
</form>
{% endfor %}
{% if user.apikey_set.all.count < max_keys %}
<form action="{% url "api_key_create" %}" method="post">
{% csrf_token %}
<tr>
<td></td>
<td><input name="comment"></td>
<td colspan="2"><input name="comment"></td>
<td><button type="submit">Create</button></td>
</tr>
</form>
{% endif %}
</tbody>
</table>
{% endblock %}
......@@ -5,6 +5,10 @@ urlpatterns = [
path('version', views.version, name='version'),
path('version/<int:version_id>', views.get_version, name='get_version'),
path('version/active', views.get_active_version, name='get_active_version'),
path('version/active/disable', views.disable_active_version, name='disable_active_version'),
path('version/<int:version_id>/disable', views.disable_version, name='disable_version'),
path('version/active/kill', views.kill_bot, name='kill_bot'),
path('version/activate/<int:version_id>', views.activate_version, name='activate_version'),
path('viewer_key', views.get_viewer_key, name='get_viewer_key'),
......
import json
from core.models import ApiKey, SnakeVersion, UserProfile
from django.http import JsonResponse, HttpResponseBadRequest
from django.forms import ModelForm
from django.core.exceptions import PermissionDenied
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from core.models import ApiKey, SnakeVersion, ServerCommand, get_user_profile
def get_user(request):
......@@ -14,11 +14,11 @@ def get_user(request):
if key is not None:
return ApiKey.objects.get(key=key)
key = request.POST.get('token', None) or request.GET.get('token', None)
key = request.GET.get('token', None)
if key is not None:
return ApiKey.objects.get(key=key)
if request.user:
if request.user.is_authenticated:
return request.user
raise PermissionDenied('API access needs login or api key')
......@@ -27,11 +27,6 @@ def get_user(request):
raise PermissionDenied('invalid API key')
def get_user_profile(user):
profile, _ = UserProfile.objects.get_or_create(user=user)
return profile
def version_dict(v):
return {
'id': v.id,
......@@ -83,7 +78,7 @@ def put_version(request):
@require_http_methods(['GET'])
def get_active_version(request, version_id):
def get_active_version(request):
user = get_user(request)
up = get_user_profile(user)
v = up.active_snake
......@@ -103,6 +98,32 @@ def activate_version(request, version_id):
return JsonResponse(version_dict(v))
@require_http_methods(['POST'])
def disable_active_version(request):
user = get_user(request)
up = get_user_profile(user)
up.active_snake = None
up.save()
return JsonResponse({'result': 'ok'})
@require_http_methods(['POST'])
def disable_version(request, version_id):
user = get_user(request)
up = get_user_profile(user)
if up.active_snake is not None and up.active_snake.id == version_id:
up.active_snake = None
up.save()
return JsonResponse({'result': 'ok'})
@require_http_methods(['POST', 'DELETE'])
def kill_bot(request):
user = get_user(request)
ServerCommand(user=user, command='kill').save()
return JsonResponse({'result': 'ok'})
@require_http_methods(['GET'])
def get_viewer_key(request):
user = get_user(request)
......@@ -114,7 +135,8 @@ def get_viewer_key(request):
@login_required()
def list_api_keys(request):
return render(request, 'api/list_api_keys.html', {
'user': request.user
'user': request.user,
'max_keys': ApiKey.MAX_KEYS_PER_USER
})
......@@ -127,6 +149,9 @@ class CreateKeyForm(ModelForm):
@require_http_methods(['POST'])
@login_required()
def create_api_key(request):
if request.user.apikey_set.count() >= ApiKey.MAX_KEYS_PER_USER:
raise SuspiciousOperation
form = CreateKeyForm(request.POST or None)
if form.is_valid():
key = ApiKey(user=request.user)
......
......@@ -5,6 +5,11 @@ from django.utils.timezone import now
from django.contrib.auth.models import User
def get_user_profile(user):
profile, _ = UserProfile.objects.get_or_create(user=user)
return profile
class SnakeVersion(models.Model):
class Meta:
get_latest_by = "created"
......@@ -89,6 +94,7 @@ def create_key():
return str(uuid.uuid4())
class ApiKey(models.Model):
MAX_KEYS_PER_USER = 20
user = models.ForeignKey(User, on_delete=models.CASCADE)
key = models.CharField(max_length=100, default=create_key())
key = models.CharField(max_length=100, default=create_key)
comment = models.CharField(max_length=255, null=True, blank=True)
......@@ -3,4 +3,8 @@
{% block content %}
<h1>Profile</h1>
<h3>API Keys</h3>
<form method="GET" action="{% url "api_keys_list" %}"><button type="submit">Manage API Keys</button></form>
<h3>Viewer Key</h3>
Websocket Viewer Key: {{ profile.viewer_key }}
{% endblock %}
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from core.models import get_user_profile
def signup(request):
if request.method == 'POST':
......@@ -18,5 +19,6 @@ def signup(request):
return render(request, 'signup.html', {'form': form})
@login_required
def profile(request):
return render(request, 'core/profile.html')
\ No newline at end of file
return render(request, 'core/profile.html', {'user': request.user, 'profile': get_user_profile(request.user)})
......@@ -6,12 +6,7 @@ from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.template.loader import render_to_string
from django.views.decorators.http import require_POST
from core.models import SnakeVersion, ServerCommand, UserProfile
def get_user_profile(user):
profile, _ = UserProfile.objects.get_or_create(user=user)
return profile
from core.models import SnakeVersion, ServerCommand, get_user_profile
class CreateSnakeForm(ModelForm):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment