-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1,175 changed files
with
87,447 additions
and
25 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
recursive-include localcosmos_server/app_admin/static * | ||
recursive-include localcosmos_server/app_admin/templates * | ||
recursive-include localcosmos_server/datasets/templates * | ||
recursive-include localcosmos_server/online_content/static * | ||
recursive-include localcosmos_server/online_content/templates * | ||
recursive-include localcosmos_server/server_control_panel/templates * | ||
recursive-include localcosmos_server/specifications * | ||
recursive-include localcosmos_server/static * | ||
recursive-include localcosmos_server/templates * |
Empty file.
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,41 @@ | ||
from django.contrib.auth import get_user_model | ||
|
||
from rest_framework.authentication import BaseAuthentication | ||
from rest_framework.authtoken.models import Token | ||
from rest_framework.exceptions import AuthenticationFailed | ||
|
||
User = get_user_model() | ||
|
||
class LCTokenAuthentication(BaseAuthentication): | ||
|
||
def authenticate(self, request): | ||
auth = request.META.get('HTTP_AUTHORIZATION', '').split() | ||
if not auth or auth[0].lower() != 'token': | ||
return None | ||
|
||
if len(auth) == 1: | ||
msg = 'Invalid token header. No credentials provided.' | ||
raise AuthenticationFailed(msg) | ||
elif len(auth) > 2: | ||
msg = 'Invalid token header. Token string should not contain spaces.' | ||
raise AuthenticationFailed(msg) | ||
|
||
key = auth[1] | ||
|
||
try: | ||
token = Token.objects.get(key=key) | ||
except Token.DoesNotExist: | ||
raise AuthenticationFailed('Invalid token') | ||
|
||
try: | ||
user = User.objects.get(pk=token.user_id) | ||
except User.DoesNotExist: | ||
raise AuthenticationFailed('User inactive or deleted') | ||
|
||
|
||
if user.is_active == True: | ||
return (user, token) | ||
|
||
else: | ||
msg = 'User inactive.' | ||
raise AuthenticationFailed(msg) |
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,65 @@ | ||
from rest_framework import permissions | ||
|
||
from localcosmos_server.models import App | ||
|
||
|
||
################################################################################################################## | ||
# | ||
# DataSet Creation | ||
# | ||
# - allow_anonymous_observations is set on an per-app-basis | ||
# - server-side check should be implemented in case the user changes this permission, otherwise old app installs could still upload | ||
# - this check uses the currently live webapp settings.json to check | ||
# | ||
################################################################################################################## | ||
|
||
class CanCreateDataset(permissions.BasePermission): | ||
|
||
def has_permission(self, request, view): | ||
|
||
app_uuid = request.data['app_uuid'] | ||
app = App.objects.get(uuid=app_uuid) | ||
|
||
review = False | ||
|
||
if 'review' in request.data: | ||
review = bool(int(request.data['review'])) | ||
|
||
api_settings = app.get_api_settings(review=review) | ||
|
||
allow_anonymous_observations = api_settings['allow_anonymous_observations'] | ||
|
||
if allow_anonymous_observations == False and request.user.is_authenticated == False: | ||
return False | ||
|
||
return True | ||
|
||
|
||
|
||
################################################################################################################### | ||
# | ||
# DataSet Management | ||
# | ||
# - only the Dataset owner may update/delete a dataset | ||
# | ||
################################################################################################################### | ||
|
||
class DatasetOwnerOnly(permissions.BasePermission): | ||
|
||
def has_object_permission(self, request, view, dataset): | ||
|
||
# allow read for all | ||
if request.method in permissions.SAFE_METHODS: | ||
return True | ||
|
||
# determine if the user is allowed to alter or delete a dataset | ||
# owner can be determined by device uuid or dataset.user == request.user | ||
if request.user == dataset.user: | ||
return True | ||
|
||
elif 'client_id' in request.query_params and request.query_params['client_id'] == dataset.client_id: | ||
return True | ||
|
||
return False | ||
|
||
|
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,39 @@ | ||
from rest_framework import permissions | ||
|
||
from django.conf import settings | ||
|
||
from django_road import permissions as road_permissions | ||
from .permissions import CanCreateDataset | ||
|
||
import os, json | ||
|
||
|
||
ROAD_MODEL_PERMISSIONS = { | ||
'LocalcosmosUser' : { | ||
'first' : [road_permissions.OwnerOnly], | ||
'default' : [road_permissions.OwnerOnly], | ||
'create' : [road_permissions.PermissionDenied], # uses separate api | ||
'fetch' : [road_permissions.PermissionDenied], # do not allow this | ||
'count' : [road_permissions.PermissionDenied], # do not allow this | ||
}, | ||
'Dataset' : { | ||
'get' : [], | ||
'filter' : [], | ||
'first' :[], | ||
'fetch' :[], | ||
'count' : [], | ||
'delete' : [road_permissions.OwnerOnly], | ||
'update' : [road_permissions.OwnerOnly], | ||
'insert' : [CanCreateDataset], # app specific permission needed | ||
}, | ||
'DatasetImages' : { | ||
'get' : [], | ||
'filter' : [], | ||
'first' :[], | ||
'fetch' :[], | ||
'count' : [], | ||
'delete' : [road_permissions.OwnerOnly], | ||
'update' : [road_permissions.OwnerOnly], | ||
'insert' : [CanCreateDataset], # app specific permission needed | ||
} | ||
} |
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,123 @@ | ||
from rest_framework import serializers | ||
from django.contrib.auth import get_user_model | ||
|
||
from localcosmos_server.datasets.models import Dataset, DatasetImages | ||
|
||
from django_road.serializer_fields import RemoteDBJSONField | ||
|
||
User = get_user_model() | ||
|
||
|
||
class LocalcosmosUserSerializer(serializers.ModelSerializer): | ||
|
||
class Meta: | ||
model = User | ||
exclude = ('password',) | ||
|
||
|
||
''' | ||
The Dataset is stored using the RemoteDB interface of the webapp | ||
OR by using the sync button on the native app | ||
''' | ||
class DatasetSerializer(serializers.ModelSerializer): | ||
|
||
assign_authenticated_user = 'user' # assigns the authenticated user to the field user on insert and update | ||
|
||
data = RemoteDBJSONField(binary=True) | ||
created_at = serializers.DateTimeField() | ||
last_modified = serializers.DateTimeField(required=False) | ||
|
||
# SerializerMethodFields are only for to_representation | ||
thumbnail = serializers.SerializerMethodField() | ||
|
||
def get_thumbnail(self, obj): | ||
|
||
image = DatasetImages.objects.filter(dataset=obj).first() | ||
|
||
if image: | ||
# App clients need the full url | ||
relative_url = image.thumbnail(size=200) | ||
url = '{0}://{1}{2}'.format(self.request.scheme, self.request.get_host(), relative_url) | ||
return url | ||
|
||
return None | ||
|
||
|
||
class Meta: | ||
model = Dataset | ||
fields = ('__all__') | ||
read_only_fields = ('user_id', 'client_id') | ||
|
||
|
||
''' | ||
DatasetImagesSerializer | ||
- keep thumbnails in sync with [App][models.js].DatasetImages.fields.image.thumbnails | ||
''' | ||
APP_THUMBNAILS = { | ||
"small" : { | ||
"size" : [100, 100], | ||
"type" : "cover" | ||
}, | ||
"medium" : { | ||
"size" : [400, 400], | ||
"type" : "cover" | ||
}, | ||
"full_hd" : { | ||
"size" : [1920, 1080], | ||
"type" : "contain" | ||
} | ||
} | ||
|
||
class FlexImageField(serializers.ImageField): | ||
|
||
def to_representation(self, image): | ||
|
||
dataset_image = image.instance | ||
|
||
host = '{0}://{1}'.format(self.parent.request.scheme, self.parent.request.get_host()) | ||
|
||
relative_url = image.url | ||
url = '{0}{1}'.format(host,relative_url) | ||
|
||
fleximage = { | ||
'url' : url, | ||
} | ||
|
||
for name, definition in APP_THUMBNAILS.items(): | ||
|
||
if definition['type'] == 'cover': | ||
relative_thumb_url = dataset_image.thumbnail(definition['size'][0]) | ||
|
||
else: | ||
relative_thumb_url = dataset_image.resized(name, max_size=definition['size']) | ||
|
||
thumb_url = '{0}{1}'.format(host, relative_thumb_url) | ||
fleximage[name] = thumb_url | ||
|
||
return fleximage | ||
|
||
|
||
''' | ||
return the DatasetImages.Dataset as a serialized Dataset | ||
''' | ||
class DatasetField(serializers.PrimaryKeyRelatedField): | ||
|
||
def to_representation(self, value): | ||
data = { | ||
'id' : value.pk | ||
} | ||
|
||
return data | ||
|
||
|
||
class DatasetImagesSerializer(serializers.ModelSerializer): | ||
|
||
# there is only 1 FK | ||
serializer_related_field = DatasetField | ||
|
||
class Meta: | ||
model = DatasetImages | ||
fields = ('__all__') | ||
|
||
from django.db.models import ImageField | ||
DatasetImagesSerializer.serializer_field_mapping[ImageField] = FlexImageField |
Oops, something went wrong.