commit
44b6a67f78
|
@ -0,0 +1,22 @@
|
|||
from rest_framework import permissions
|
||||
|
||||
|
||||
class SafeMethodsOnlyPermission(permissions.BasePermission):
|
||||
"""Anyone can access non-destructive methods (like GET and HEAD)"""
|
||||
def has_permission(self, request, view):
|
||||
return self.has_object_permission(request, view)
|
||||
|
||||
def has_object_permission(self, request, view, obj=None):
|
||||
return request.method in permissions.SAFE_METHODS
|
||||
|
||||
|
||||
class StationOwnerCanEditPermission(SafeMethodsOnlyPermission):
|
||||
"""Only the owner can push new data"""
|
||||
def has_object_permission(self, request, view, obj=None):
|
||||
if obj is None:
|
||||
can_edit = True
|
||||
else:
|
||||
can_edit = request.user == obj.observation.author
|
||||
return (can_edit or
|
||||
super(StationOwnerCanEditPermission,
|
||||
self).has_object_permission(request, view, obj))
|
|
@ -16,7 +16,7 @@ class StationSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Station
|
||||
fields = ('owner', 'name', 'image', 'alt', 'lat', 'lng',
|
||||
'antenna', 'featured', 'featured_date')
|
||||
'antenna', 'featured_date', 'id')
|
||||
|
||||
image = serializers.SerializerMethodField('image_url')
|
||||
|
||||
|
@ -48,4 +48,4 @@ class ObservationSerializer(serializers.ModelSerializer):
|
|||
class DataSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Data
|
||||
fields = ('start', 'end', 'observation', 'ground_station', 'payload')
|
||||
fields = ('id', 'start', 'end', 'observation', 'ground_station', 'payload')
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf.urls import patterns, url, include
|
||||
from rest_framework import routers
|
||||
|
||||
from base.api import views
|
||||
from api import views
|
||||
|
||||
|
||||
router = routers.DefaultRouter()
|
|
@ -1,6 +1,7 @@
|
|||
from rest_framework import viewsets
|
||||
from rest_framework import viewsets, mixins
|
||||
|
||||
from base.api import serializers
|
||||
from api.perms import StationOwnerCanEditPermission
|
||||
from api import serializers
|
||||
from base.models import (Antenna, Data, Observation, Satellite, Station,
|
||||
Transponder)
|
||||
|
||||
|
@ -30,6 +31,10 @@ class ObservationView(viewsets.ModelViewSet):
|
|||
serializer_class = serializers.ObservationSerializer
|
||||
|
||||
|
||||
class DataView(viewsets.ModelViewSet):
|
||||
class DataView(viewsets.ReadOnlyModelViewSet,
|
||||
mixins.UpdateModelMixin):
|
||||
queryset = Data.objects.all()
|
||||
serializer_class = serializers.DataSerializer
|
||||
permission_classes = [
|
||||
StationOwnerCanEditPermission
|
||||
]
|
|
@ -8,4 +8,4 @@ class StationForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = Station
|
||||
fields = ['name', 'image', 'alt',
|
||||
'lat', 'lng', 'antenna', 'online']
|
||||
'lat', 'lng', 'antenna', 'online']
|
||||
|
|
|
@ -39,13 +39,15 @@ class Common(Configuration):
|
|||
THIRD_PARTY_APPS = (
|
||||
'crispy_forms', # Form layouts
|
||||
'avatar', # for user avatars
|
||||
'rest_framework'
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken'
|
||||
)
|
||||
|
||||
# Apps specific for this project go here.
|
||||
LOCAL_APPS = (
|
||||
'users', # custom users app
|
||||
'users',
|
||||
'base',
|
||||
'api',
|
||||
'django_extensions',
|
||||
)
|
||||
|
||||
|
@ -183,7 +185,7 @@ class Common(Configuration):
|
|||
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
||||
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
|
||||
STATICFILES_DIRS = (
|
||||
join(BASE_DIR, 'static'),
|
||||
)
|
||||
|
@ -266,9 +268,10 @@ class Common(Configuration):
|
|||
# END LOGGING CONFIGURATION
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
# Use Django's standard `django.contrib.auth` permissions,
|
||||
# or allow read-only access for unauthenticated users.
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
|
||||
]
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
|
||||
),
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
{% block title %}SatNOGS Network API{% endblock %}
|
||||
|
||||
{% block branding %}
|
||||
<a class='brand' rel="nofollow" href='#'>
|
||||
SatNOGS Network API <span class="version">1.0</span>
|
||||
</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<p>2014 - The SatNOGS devs</p>
|
||||
<a class="navbar-brand" rel="nofollow" href="#">
|
||||
SatNOGS Network API <span class="version"></span>
|
||||
</a>
|
||||
{% endblock %}
|
|
@ -15,7 +15,8 @@
|
|||
<div class="pull-right edit-profile-buttons">
|
||||
<a class="btn btn-primary" href="{% url 'users:update' %}">My Info</a>
|
||||
<a class="btn btn-primary" href="{% url 'account_email' %}">E-Mail</a>
|
||||
<a class="btn btn-info" href="{% url 'avatar_change' %}">Avatar</a>
|
||||
<a class="btn btn-primary" href="{% url 'avatar_change' %}">Avatar</a>
|
||||
<a class="btn btn-info" data-toggle="modal" data-target="#APIModal" href="#">API Key</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h2>
|
||||
|
@ -133,9 +134,29 @@
|
|||
|
||||
</div>
|
||||
|
||||
<!-- API Modal -->
|
||||
<div class="modal fade" id="APIModal" tabindex="-1" role="dialog" aria-labelledby="APIModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="APIModalLabel">API Key</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div>You can use this token to interact with the API.</div>
|
||||
<div>
|
||||
<code>{{ token }}</code>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Station Modal -->
|
||||
<div class="modal fade" id="StationModal" tabindex="-1" role="dialog" aria-labelledby="StationModal" aria-hidden="true">
|
||||
<div class="modal fade" id="StationModal" tabindex="-1" role="dialog" aria-labelledby="StationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
|
|
@ -20,7 +20,7 @@ urlpatterns = patterns(
|
|||
url(r'^accounts/', include('allauth.urls')),
|
||||
url(r'^avatar/', include('avatar.urls')),
|
||||
|
||||
url(r'^api/', include('base.api.urls'))
|
||||
url(r'^api/', include('api.urls'))
|
||||
)
|
||||
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core.validators import MaxLengthValidator
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
|
||||
|
||||
def gen_token(sender, instance, created, **kwargs):
|
||||
try:
|
||||
Token.objects.get(user=instance)
|
||||
except:
|
||||
Token.objects.create(user=instance)
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
|
@ -11,3 +20,5 @@ class User(AbstractUser):
|
|||
|
||||
def __unicode__(self):
|
||||
return self.username
|
||||
|
||||
post_save.connect(gen_token, sender=User)
|
||||
|
|
|
@ -8,6 +8,8 @@ from django.views.generic import ListView
|
|||
|
||||
from braces.views import LoginRequiredMixin
|
||||
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from .forms import UserForm
|
||||
from .models import User
|
||||
from base.forms import StationForm
|
||||
|
@ -54,6 +56,10 @@ def view_user(request, username):
|
|||
user = User.objects.get(username=username)
|
||||
observations = Observation.objects.filter(author=user)[0:10]
|
||||
stations = Station.objects.filter(owner=user)
|
||||
try:
|
||||
token = Token.objects.get(user=user)
|
||||
except:
|
||||
token = Token.objects.create(user=user)
|
||||
form = StationForm()
|
||||
if request.method == 'POST':
|
||||
form = StationForm(request.POST, request.FILES)
|
||||
|
@ -69,4 +75,5 @@ def view_user(request, username):
|
|||
{'user': user,
|
||||
'observations': observations,
|
||||
'stations': stations,
|
||||
'token': token,
|
||||
'form': form})
|
||||
|
|
|
@ -31,6 +31,6 @@ django-autoslug==1.7.2
|
|||
orbit==0.2
|
||||
|
||||
# Django REST framework
|
||||
djangorestframework
|
||||
djangorestframework==3.0.1
|
||||
markdown
|
||||
django-filter
|
||||
django-filter
|
||||
|
|
|
@ -4,4 +4,5 @@ Sphinx
|
|||
|
||||
# django-debug-toolbar that works with Django 1.5+
|
||||
django-debug-toolbar==1.2.1
|
||||
sqlparse==0.1.14
|
||||
factory_boy
|
||||
|
|
Loading…
Reference in New Issue