From 33e0e58b5ef02c5a5603bcf5fa7f640bb420b785 Mon Sep 17 00:00:00 2001 From: Fergal Moran Date: Sun, 12 Jul 2015 15:06:49 +0100 Subject: [PATCH] Pre feature branch --- INSTALL | 2 +- api/auth.py | 122 +------------------------------------- api/helpers.py | 24 ++++++-- api/old_auth.py | 120 +++++++++++++++++++++++++++++++++++++ api/urls.py | 1 + api/views.py | 14 ++--- core/realtime/activity.py | 24 ++++---- core/realtime/chat.py | 8 +++ core/utils/session.py | 20 +++++++ requirements.txt | 3 + spa/models/basemodel.py | 8 +-- 11 files changed, 194 insertions(+), 152 deletions(-) mode change 100755 => 100644 api/auth.py create mode 100755 api/old_auth.py create mode 100644 core/realtime/chat.py create mode 100644 core/utils/session.py diff --git a/INSTALL b/INSTALL index 9bd9ae2..91df2a4 100755 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,6 @@ #curl -u hb_client_2862_1:j2CbCM8H -H 'Accept: application/json' -H 'Content-type: application/json' http://c1.lon2.dediserve.com/virtual_machines.xml -apt-get install git python-virtualenv postgresql-common libsndfile1-dev libpng++-dev libpng12-dev libboost-program-options-dev libjpeg-dev python-dev libsox-fmt-mp3 +apt-get install git python-virtualenv postgresql-common libsndfile1-dev libpng++-dev libpng12-dev libboost-program-options-dev libjpeg-dev python-dev libsox-fmt-mp3 postgresql-server-dev-all postgresql-client virtualenv env source env/bin/activate diff --git a/api/auth.py b/api/auth.py old mode 100755 new mode 100644 index affbf14..6d4caf8 --- a/api/auth.py +++ b/api/auth.py @@ -1,121 +1 @@ -from requests import HTTPError -from rest_framework import parsers -from rest_framework.authentication import get_authorization_header -from rest_framework.authtoken.models import Token -from rest_framework.authtoken.serializers import AuthTokenSerializer -from rest_framework.response import Response -from rest_framework.status import * -from rest_framework.views import APIView -from rest_framework import status -from rest_framework import renderers -from social.apps.django_app.utils import strategy, load_strategy, load_backend -from dss import settings - - -class LoginException(Exception): - pass - - -@strategy() -def register_by_access_token(request, backend): - auth = get_authorization_header(request).split() - if not auth or auth[0].lower() != b'social': - raise LoginException("Unable to register_by_access_token: No token header provided") - - access_token = auth[1] - return request.backend.do_auth(access_token) -""" -class RefreshTokenView(APIView): - serializer_class = AuthTokenSerializer - model = Token - - def post(self, request): - # Here we call PSA to authenticate like we would if we used PSA on server side. - try: - backend = request.META.get('HTTP_AUTH_BACKEND') - if backend is None: - # Work around django test client oddness - return Response("No Auth-Backend header specified", HTTP_400_BAD_REQUEST) - - user = refresh_access_token(request, backend) - - # If user is active we get or create the REST token and send it back with user data - if user and user.is_active: - token, created = Token.objects.get_or_create(user=user) - return Response({ - 'slug': user.userprofile.slug, - 'token': token.key - }) - except LoginException, ex: - return Response(ex.message, HTTP_400_BAD_REQUEST) - except HTTPError, ex: - if ex.response.status_code == 400: - return Response(ex.message, HTTP_401_UNAUTHORIZED) - return Response(ex.message, HTTP_400_BAD_REQUEST) -""" - -class ObtainAuthToken(APIView): - serializer_class = AuthTokenSerializer - model = Token - - def post(self, request): - # Here we call PSA to authenticate like we would if we used PSA on server side. - try: - backend = request.META.get('HTTP_AUTH_BACKEND') - if backend is None: - # Work around django test client oddness - return Response("No Auth-Backend header specified", HTTP_400_BAD_REQUEST) - - user = register_by_access_token(request, backend) - - # If user is active we get or create the REST token and send it back with user data - if user and user.is_active: - token, created = Token.objects.get_or_create(user=user) - return Response({ - 'slug': user.userprofile.slug, - 'token': token.key - }) - except LoginException, ex: - return Response(ex.message, HTTP_400_BAD_REQUEST) - except HTTPError, ex: - if ex.response.status_code == 400: - return Response(ex.message, HTTP_401_UNAUTHORIZED) - return Response(ex.message, HTTP_400_BAD_REQUEST) - - -class ObtainUser(APIView): - throttle_classes = () - permission_classes = () - parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) - renderer_classes = (renderers.JSONRenderer,) - serializer_class = AuthTokenSerializer - model = Token - - def get(self, request): - if request.META.get('HTTP_AUTHORIZATION'): - - auth = request.META.get('HTTP_AUTHORIZATION').split() - - if not auth or auth[0].lower() != b'token' or len(auth) != 2: - msg = 'Invalid token header. No credentials provided.' - return Response(msg, status=status.HTTP_401_UNAUTHORIZED) - - token = Token.objects.get(key=auth[1]) - if token and token.user.is_active: - return Response({'id': token.user_id, 'name': token.user.username, 'firstname': token.user.first_name, - 'userRole': 'user', 'token': token.key}) - else: - return Response(status=status.HTTP_401_UNAUTHORIZED) - - -class ObtainLogout(APIView): - throttle_classes = () - permission_classes = () - parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) - renderer_classes = (renderers.JSONRenderer,) - serializer_class = AuthTokenSerializer - model = Token - - # Logout le user - def get(self, request): - return Response({'User': ''}) +__author__ = 'fergalm' diff --git a/api/helpers.py b/api/helpers.py index ccd7c70..2aa1d3b 100644 --- a/api/helpers.py +++ b/api/helpers.py @@ -4,21 +4,35 @@ from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_201_CREATED, HTTP_2 from rest_framework.views import APIView from dss import settings from spa.models import Mix, UserProfile - +from core.utils import session class Helper(APIView): pass class ActivityHelper(APIView): - pass + def get_session(self, request): + sessions = session.get_active_sessions(request.session) + + return sessions[0] + + +class ChatHelper(ActivityHelper): + def post(self, request): + # do some persistence stuff with the chat + from core.realtime import chat + + user = self.get_session(request) + + chat.post_chat(request.DATA['user'], request.DATA['message']) + return Response(request.DATA['message'], HTTP_201_CREATED) class ActivityPlayHelper(ActivityHelper): def post(self, request): - if 'id' in self.request.QUERY_PARAMS: + if 'id' in self.request.query_params: try: - mix = Mix.objects.get(slug=self.request.QUERY_PARAMS.get('id')) + mix = Mix.objects.get(slug=self.request.query_params.get('id')) mix.add_play(request.user) data = { 'user': request.user.userprofile.get_nice_name() if request.user.is_authenticated() else settings.DEFAULT_USER_NAME, @@ -34,7 +48,7 @@ class ActivityPlayHelper(ActivityHelper): class UserSlugCheckHelper(Helper): def get(self, request): try: - UserProfile.objects.get(slug=self.request.QUERY_PARAMS.get('slug')) + UserProfile.objects.get(slug=self.request.query_params.get('slug')) return Response(status=HTTP_204_NO_CONTENT) except UserProfile.DoesNotExist: return Response(status=HTTP_200_OK) diff --git a/api/old_auth.py b/api/old_auth.py new file mode 100755 index 0000000..7c41c2f --- /dev/null +++ b/api/old_auth.py @@ -0,0 +1,120 @@ +from requests import HTTPError +from rest_framework import parsers +from rest_framework.authentication import get_authorization_header +from rest_framework.authtoken.models import Token +from rest_framework.authtoken.serializers import AuthTokenSerializer +from rest_framework.response import Response +from rest_framework.status import * +from rest_framework.views import APIView +from rest_framework import status +from rest_framework import renderers +from social.apps.django_app.utils import psa + + +class LoginException(Exception): + pass + + +@psa() +def register_by_access_token(request, backend): + auth = get_authorization_header(request).split() + if not auth or auth[0].lower() != b'social': + raise LoginException("Unable to register_by_access_token: No token header provided") + + access_token = auth[1] + return request.backend.do_auth(access_token) +""" +class RefreshTokenView(APIView): + serializer_class = AuthTokenSerializer + model = Token + + def post(self, request): + # Here we call PSA to authenticate like we would if we used PSA on server side. + try: + backend = request.META.get('HTTP_AUTH_BACKEND') + if backend is None: + # Work around django test client oddness + return Response("No Auth-Backend header specified", HTTP_400_BAD_REQUEST) + + user = refresh_access_token(request, backend) + + # If user is active we get or create the REST token and send it back with user data + if user and user.is_active: + token, created = Token.objects.get_or_create(user=user) + return Response({ + 'slug': user.userprofile.slug, + 'token': token.key + }) + except LoginException, ex: + return Response(ex.message, HTTP_400_BAD_REQUEST) + except HTTPError, ex: + if ex.response.status_code == 400: + return Response(ex.message, HTTP_401_UNAUTHORIZED) + return Response(ex.message, HTTP_400_BAD_REQUEST) +""" + +class ObtainAuthToken(APIView): + serializer_class = AuthTokenSerializer + model = Token + + def post(self, request): + # Here we call PSA to authenticate like we would if we used PSA on server side. + try: + backend = request.META.get('HTTP_AUTH_BACKEND') + if backend is None: + # Work around django test client oddness + return Response("No Auth-Backend header specified", HTTP_400_BAD_REQUEST) + + user = register_by_access_token(request, backend) + + # If user is active we get or create the REST token and send it back with user data + if user and user.is_active: + token, created = Token.objects.get_or_create(user=user) + return Response({ + 'slug': user.userprofile.slug, + 'token': token.key + }) + except LoginException, ex: + return Response(ex.message, HTTP_400_BAD_REQUEST) + except HTTPError, ex: + if ex.response.status_code == 400: + return Response(ex.message, HTTP_401_UNAUTHORIZED) + return Response(ex.message, HTTP_400_BAD_REQUEST) + + +class ObtainUser(APIView): + throttle_classes = () + permission_classes = () + parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) + renderer_classes = (renderers.JSONRenderer,) + serializer_class = AuthTokenSerializer + model = Token + + def get(self, request): + if request.META.get('HTTP_AUTHORIZATION'): + + auth = request.META.get('HTTP_AUTHORIZATION').split() + + if not auth or auth[0].lower() != b'token' or len(auth) != 2: + msg = 'Invalid token header. No credentials provided.' + return Response(msg, status=status.HTTP_401_UNAUTHORIZED) + + token = Token.objects.get(key=auth[1]) + if token and token.user.is_active: + return Response({'id': token.user_id, 'name': token.user.username, 'firstname': token.user.first_name, + 'userRole': 'user', 'token': token.key}) + else: + return Response(status=status.HTTP_401_UNAUTHORIZED) + + +class ObtainLogout(APIView): + throttle_classes = () + permission_classes = () + parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) + renderer_classes = (renderers.JSONRenderer,) + serializer_class = AuthTokenSerializer + model = Token + + # Logout le user + def get(self, request): + return Response({'User': ''}) diff --git a/api/urls.py b/api/urls.py index d2738eb..d0b1b0a 100755 --- a/api/urls.py +++ b/api/urls.py @@ -34,6 +34,7 @@ urlpatterns = patterns( url(r'^_act/play', helpers.ActivityPlayHelper.as_view()), + url(r'^_chat/', helpers.ChatHelper.as_view()), url('', include('social.apps.django_app.urls', namespace='social')), ) diff --git a/api/views.py b/api/views.py index ce00a96..e6546e9 100755 --- a/api/views.py +++ b/api/views.py @@ -75,10 +75,10 @@ class UserProfileViewSet(viewsets.ModelViewSet): ) def get_queryset(self): - if 'following' in self.request.QUERY_PARAMS: - ret = UserProfile.objects.filter(following__slug__in=[self.request.QUERY_PARAMS['following']]) - elif 'followers' in self.request.QUERY_PARAMS: - ret = UserProfile.objects.filter(followers__slug__in=[self.request.QUERY_PARAMS['followers']]) + if 'following' in self.request.query_params: + ret = UserProfile.objects.filter(following__slug__in=[self.request.query_params['following']]) + elif 'followers' in self.request.query_params: + ret = UserProfile.objects.filter(followers__slug__in=[self.request.query_params['followers']]) else: ret = super(UserProfileViewSet, self).get_queryset() @@ -104,7 +104,7 @@ class MixViewSet(viewsets.ModelViewSet): return Response({'url': mix.get_stream_url()}) def get_queryset(self): - if 'friends' in self.request.QUERY_PARAMS: + if 'friends' in self.request.query_params: if self.request.user.is_authenticated(): rows = Mix.objects.filter(user__in=self.request.user.userprofile.following.all()) return rows @@ -242,10 +242,10 @@ class GenreViewSet(viewsets.ModelViewSet): serializer_class = serializers.GenreSerializer def get_queryset(self): - if 'q' in self.request.QUERY_PARAMS: + if 'q' in self.request.query_params: rows = Genre.objects \ .annotate(used=Count('mix')) \ - .filter(description__icontains=self.request.QUERY_PARAMS['q']) \ + .filter(description__icontains=self.request.query_params['q']) \ .only('description') \ .order_by('-used') return rows diff --git a/core/realtime/activity.py b/core/realtime/activity.py index 9ad8562..1ed2ef0 100755 --- a/core/realtime/activity.py +++ b/core/realtime/activity.py @@ -1,16 +1,12 @@ -import requests -from core.serialisers import json -from dss import localsettings, settings +import redis +import json -def post_activity(session_id, activity_url): - payload = { - 'sessionid': session_id, - 'message': activity_url - } - data = json.dumps(payload) - r = requests.post(localsettings.REALTIME_HOST + 'activity', data=data, headers=settings.REALTIME_HEADERS) - if r.status_code == 200: - return "" - else: - return r.text +def post_activity(channel, session, message): + r = redis.StrictRedis(host='localhost', port=6379, db=0) + response = r.publish(channel, json.dumps({'session': session, 'message': message})) + print "Message sent: {0}".format(response) + +if __name__ == '__main__': + post_activity('site:broadcast', '3a596ca6c97065a67aca3dc4a3ba230d688cf413', 'bargle') + diff --git a/core/realtime/chat.py b/core/realtime/chat.py new file mode 100644 index 0000000..e981a5e --- /dev/null +++ b/core/realtime/chat.py @@ -0,0 +1,8 @@ +import json +import redis + + +def post_chat(session, message): + r = redis.StrictRedis(host='localhost', port=6379, db=0) + response = r.publish('chat', json.dumps({'session': session, 'message': message})) + print "Message sent: {0}".format(response) diff --git a/core/utils/session.py b/core/utils/session.py new file mode 100644 index 0000000..ef38323 --- /dev/null +++ b/core/utils/session.py @@ -0,0 +1,20 @@ +from django.contrib.sessions.models import Session +from django.utils import timezone + + +def get_active_sessions(session): + # Query all non-expired sessions + # use timezone.now() instead of datetime.now() in latest versions of Django + sessions = Session.objects.filter(expire_date__gte=timezone.now()) + if session is not None: + sessions = sessions.filter(session_id=session.id) + uid_list = [] + + # Build a list of user ids from that query + for session in sessions: + data = session.get_decoded() + uid_list.append(data.get('_auth_user_id', None)) + + # Query all logged in users based on id list + from spa.models import UserProfile + return UserProfile.objects.filter(user_id__in=uid_list) diff --git a/requirements.txt b/requirements.txt index 9d65559..bb51a4d 100755 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ django-model_utils django-dbbackup django-user-agents south +redis sorl-thumbnail @@ -24,6 +25,8 @@ git+git://github.com/Azure/azure-sdk-for-python.git#azure git+git://github.com/tschellenbach/Django-facebook.git#django-facebook git+git://github.com/llazzaro/django-scheduler.git#django-scheduler git+git://github.com/omab/python-social-auth.git#egg=python-social-auth +django-allauth +django-tinymce apache-libcloud mandrill djrill diff --git a/spa/models/basemodel.py b/spa/models/basemodel.py index eb8e78b..7f15512 100755 --- a/spa/models/basemodel.py +++ b/spa/models/basemodel.py @@ -1,14 +1,14 @@ import logging import os from datetime import datetime -from dirtyfields import DirtyFieldsMixin +import json + from django.db import models -from django.utils import simplejson + from core.utils import url from dss import localsettings, settings - class BaseModel(models.Model): logger = logging.getLogger(__name__) @@ -20,7 +20,7 @@ class BaseModel(models.Model): app_label = 'spa' def tosimplejson(self): - return simplejson.dump(self) + return json.dumps(self) @classmethod def get_lookup(cls, filter_field, transform=None, filter=None):