diff --git a/README.org b/README.org index 4531215..a7a55f0 100644 --- a/README.org +++ b/README.org @@ -5,7 +5,6 @@ Repository for the maidstone hackspace website, feel free to fork this site for your own Hackspace. - ** Requirements Before getting started make sure you have git, docker and docker-compose installed on your machine. The simplest way to setup this site is to use docker-compose so please install that from this site @@ -47,7 +46,7 @@ docker-compose -f dev.yml run --rm django python manage.py makemigrations docker-compose -f dev.yml run --rm django python manage.py migrate #+END_SRC *** Create the admin user. -Once created you can login at http://127.0.0.1:8180/admin +Once created you can login at http://127.0.0.1:8180/trustee #+BEGIN_SRC sh docker-compose -f dev.yml run --rm django python manage.py createsuperuser #+END_SRC diff --git a/config/settings/common.py b/config/settings/common.py index 1ac9c19..f954c7a 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -80,6 +80,7 @@ THIRD_PARTY_APPS = ( 'whitenoise.runserver_nostatic', 'stdimage', 'rest_framework', + 'django_filters', 'draceditor', 'haystack', 'djconfig', @@ -138,6 +139,7 @@ LOCAL_APPS = ( 'mhackspace.blog', 'mhackspace.core', 'mhackspace.requests', + 'mhackspace.rfid', ) # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps @@ -446,10 +448,12 @@ REST_FRAMEWORK = { 'rest_framework.filters.OrderingFilter' ), 'DEFAULT_PERMISSION_CLASSES': ( - 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', + # 'rest_framework.permissions.IsAuthenticated', + # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework.authentication.BasicAuthentication', + # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', + # 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ), diff --git a/config/urls.py b/config/urls.py index 4595b9d..e078d3e 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals + from django.conf import settings from django.conf.urls import include, url from django.conf.urls.static import static @@ -9,6 +10,7 @@ from django.views import defaults as default_views from django.contrib.auth import views as auth_views from django.contrib.sitemaps.views import sitemap from rest_framework.routers import DefaultRouter +from rest_framework.documentation import include_docs_urls from mhackspace.contact.views import contact from mhackspace.members.views import MemberListView @@ -20,21 +22,28 @@ from mhackspace.blog.views import PostViewSet, CategoryViewSet, BlogPost, PostLi from mhackspace.blog.sitemaps import PostSitemap, CategorySitemap from mhackspace.feeds.views import FeedViewSet, ArticleViewSet from mhackspace.requests.views import RequestsForm, RequestsList +from mhackspace.rfid.views import DeviceViewSet, AuthUserWithDeviceViewSet + from wiki.urls import get_pattern as get_wiki_pattern from django_nyt.urls import get_pattern as get_nyt_pattern +from rest_framework_jwt.views import obtain_jwt_token router = DefaultRouter() router.register(r'posts', PostViewSet) router.register(r'categories', CategoryViewSet) router.register(r'feeds', FeedViewSet) router.register(r'articles', ArticleViewSet) +router.register(r'rfid', DeviceViewSet) +router.register(r'rfidAuth', AuthUserWithDeviceViewSet, base_name='device') + sitemaps = { 'posts': PostSitemap, 'category': CategorySitemap, } + urlpatterns = [ url(r'^$', TemplateView.as_view(template_name='pages/home.html'), name='home'), url(r'^about/$', TemplateView.as_view(template_name='pages/about.html'), name='about'), @@ -68,6 +77,9 @@ urlpatterns = [ # Django Admin, use {% url 'admin:index' %} url(r'{}'.format(settings.ADMIN_URL), admin.site.urls), + url(r'^api-token-auth/', obtain_jwt_token), + url(r'^api/docs/', include_docs_urls(title='Hackspace API')), + # User management url(r'^users/', include('mhackspace.users.urls', namespace='users')), url(r'^accounts/', include('allauth.urls')), diff --git a/mhackspace/rfid/__init__.py b/mhackspace/rfid/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mhackspace/rfid/admin.py b/mhackspace/rfid/admin.py new file mode 100644 index 0000000..0a8621d --- /dev/null +++ b/mhackspace/rfid/admin.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from django.contrib import admin +from django.contrib.admin import ModelAdmin + +from mhackspace.rfid.models import Device, Rfid + + +@admin.register(Device) +class DeviceAdmin(ModelAdmin): + list_display = ('name',) + +@admin.register(Rfid) +class RfidAdmin(ModelAdmin): + list_display = ('code',) diff --git a/mhackspace/rfid/migrations/0001_initial.py b/mhackspace/rfid/migrations/0001_initial.py new file mode 100644 index 0000000..fb37b39 --- /dev/null +++ b/mhackspace/rfid/migrations/0001_initial.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-04-14 21:15 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Device', + fields=[ + ('identifier', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255, verbose_name='Device name')), + ('description', models.CharField(blank=True, max_length=255, verbose_name='Short description of what the device does')), + ('added_date', models.DateTimeField(default=django.utils.timezone.now, editable=False)), + ], + ), + migrations.CreateModel( + name='DeviceAuth', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('device', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='device', to='rfid.Device')), + ('user', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_auth', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Rfid', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.PositiveIntegerField()), + ('description', models.CharField(blank=True, max_length=255, verbose_name='Short rfid description')), + ('user', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rfid_user', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/mhackspace/rfid/migrations/0002_auto_20170420_0730.py b/mhackspace/rfid/migrations/0002_auto_20170420_0730.py new file mode 100644 index 0000000..da8ec64 --- /dev/null +++ b/mhackspace/rfid/migrations/0002_auto_20170420_0730.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-04-20 07:30 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('rfid', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='deviceauth', + name='device', + ), + migrations.RemoveField( + model_name='deviceauth', + name='user', + ), + migrations.AddField( + model_name='device', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='rfid', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.DeleteModel( + name='DeviceAuth', + ), + ] diff --git a/mhackspace/rfid/migrations/__init__.py b/mhackspace/rfid/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mhackspace/rfid/models.py b/mhackspace/rfid/models.py new file mode 100644 index 0000000..3b727ed --- /dev/null +++ b/mhackspace/rfid/models.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, absolute_import +import uuid + +from django.utils import timezone +from django.conf import settings +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +# just brainstorming so we can start playing with this, +# be nice to make this a 3rd party django installable app ? + + +# users rfid card to user mapping, user can have more than one card +class Rfid(models.Model): + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + null=True, blank=True, + # related_name='rfid_user' + ) + code = models.PositiveIntegerField() + description = models.CharField(_('Short rfid description'), blank=True, max_length=255) + + def __str__(self): + return self.description + + +# description of a device like door, print, laser cutter +class Device(models.Model): + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + null=True, blank=True, + # related_name='rfid_user' + ) + # user = models.ManyToMany(settings.AUTH_USER_MODEL) + identifier = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + + name = models.CharField(_('Device name'), max_length=255) + description = models.CharField(_('Short description of what the device does'), blank=True, max_length=255) + added_date = models.DateTimeField(default=timezone.now, editable=False) + + def __str__(self): + return self.name + + +# many to many, lookup user from rfid model then get there user_id and the device to check if auth allowed +# class DeviceAuth(models.Model): +# user = models.ForeignKey( +# settings.AUTH_USER_MODEL, +# null=True, blank=True, +# default=None, +# related_name='user_auth' +# ) + +# device = models.ForeignKey( +# Device, +# null=True, blank=True, +# default=None, +# related_name='device' +# ) diff --git a/mhackspace/rfid/serializers.py b/mhackspace/rfid/serializers.py new file mode 100644 index 0000000..f5db4ff --- /dev/null +++ b/mhackspace/rfid/serializers.py @@ -0,0 +1,32 @@ +from rest_framework import serializers + +from mhackspace.rfid.models import Device + + +class Task(object): + def __init__(self, **kwargs): + for field in ('id', 'name', 'owner', 'status'): + setattr(self, field, kwargs.get(field, None)) + + +class DeviceSerializer(serializers.ModelSerializer): + class Meta: + model = Device + fields = ('name', ) + + +class AuthSerializer(serializers.Serializer): + name = serializers.CharField(max_length=255) + rfid = serializers.CharField(max_length=255) + device_id = serializers.CharField(max_length=255) + + # def create(self, validated_data): + # return Task(id=None, **validated_data) + + # def update(self, instance, validated_data): + # for field, value in validated_data.items(): + # setattr(instance, field, value) + # return instance + + # class Meta: + # fields = ('name', ) diff --git a/mhackspace/rfid/tests/__init__.py b/mhackspace/rfid/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mhackspace/rfid/tests/tests.py b/mhackspace/rfid/tests/tests.py new file mode 100644 index 0000000..d9537ef --- /dev/null +++ b/mhackspace/rfid/tests/tests.py @@ -0,0 +1,58 @@ +import sys +import requests + +from io import StringIO +from django.core.management import call_command +from test_plus.test import TestCase +from rest_framework.test import APIRequestFactory +from rest_framework.test import RequestsClient + +from mhackspace.rfid.models import Device +from mhackspace.user.models import User + + +# http://www.django-rest-framework.org/api-guide/testing/ + +class MigrationTestCase(TestCase): + + def testRollback(self): + out = StringIO() + sys.stout = out + call_command('migrate', 'rfid', 'zero', stdout=out) + call_command('migrate', 'rfid', stdout=out) + self.assertIn("... OK\n", out.getvalue()) + +class ApiTests(TestCase): + def setUp(self): + Device(name='device01').save() + User(name='User01').save() + Rfid(code=1, user=1).save() + + def testAuth(self): + factory = APIRequestFactory() + request = factory.get('/rfid/') + + def testSamsMadness(self): + client = RequestsClient() + response = client.post( + 'http://127.0.0.1:8180/api/v1/rfidAuth/?format=json', + data={'rfid':'1', 'device': '1'}) + print(response) + assert response.status_code == 200 + self.assertEquals(response.json().get('results'), [{'name': 'device01'}]) + + + def testAuthUserWithDevice(self): + client = RequestsClient() + response = client.get('http://127.0.0.1:8180/api/v1/rfid/?format=json') + assert response.status_code == 200 + self.assertEquals(response.json().get('results'), [{'name': 'device01'}]) + + + def testFetchDeviceList(self): + client = RequestsClient() + response = client.get('http://127.0.0.1:8180/api/v1/rfid/?format=json') + assert response.status_code == 200 + self.assertEquals(response.json().get('results'), [{'name': 'device01'}]) + + diff --git a/mhackspace/rfid/views.py b/mhackspace/rfid/views.py new file mode 100644 index 0000000..e1648af --- /dev/null +++ b/mhackspace/rfid/views.py @@ -0,0 +1,32 @@ +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework import viewsets +from mhackspace.rfid.models import Device, Rfid +from mhackspace.rfid.serializers import DeviceSerializer, AuthSerializer +from django.shortcuts import get_list_or_404, get_object_or_404 + + +class DeviceViewSet(viewsets.ModelViewSet): + queryset = Device.objects.all() + serializer_class = DeviceSerializer + + +#https://medium.com/django-rest-framework/django-rest-framework-viewset-when-you-don-t-have-a-model-335a0490ba6f +class AuthUserWithDeviceViewSet(viewsets.ViewSet): + # http_method_names = ['get', 'post', 'head'] + serializer_class = AuthSerializer + + def list(self, request): + serializer = AuthSerializer(instance={'name': '1','rfid': '1', 'device_id': '1'}) + return Response(serializer.data) + + def post(self, request, format=None): + rfid = Rfid.objects.get(code=request.GET.get('rfid_id')) + + print(rfid.user.device__set(device=request.GET.get('rfid_id'))) + # = get_object_or_404(Disease, pk=disease_id) + + + # Device(rfid, device) + serializer = AuthSerializer(instance={'name': '1', 'rfid': '1', 'device_id': '1'}) + return Response(serializer.data) diff --git a/mhackspace/static/sass/project.scss b/mhackspace/static/sass/project.scss index 6aceb3b..6e7afd3 100644 --- a/mhackspace/static/sass/project.scss +++ b/mhackspace/static/sass/project.scss @@ -21,3 +21,9 @@ [hidden][style="display: block;"] { display: block !important; } + +.imgfit { + width:100%; + height: auto; + overflow: hidden; +} \ No newline at end of file diff --git a/requirements/base.txt b/requirements/base.txt index 22a23a7..353bb77 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -61,7 +61,10 @@ git+https://github.com/olymk2/scaffold.git git+git://github.com/django-wiki/django-wiki.git djangorestframework==3.6.3 +djangorestframework-jwt django-filter==1.0.2 +coreapi +# api libraries end draceditor==1.1.8 # django-spirit