diff --git a/greenmine/base/serializers.py b/greenmine/base/serializers.py new file mode 100644 index 00000000..3f78e600 --- /dev/null +++ b/greenmine/base/serializers.py @@ -0,0 +1,34 @@ +from rest_framework import serializers + +class UserLogged(object): + def __init__(self, token, username, first_name, last_name, email, last_login): + self.token = token + self.username = username + self.first_name = first_name + self.last_name = last_name + self.email = email + self.last_login = last_login + + +class LoginSerializer(serializers.Serializer): + token = serializers.CharField(max_length=40) + username = serializers.CharField(max_length=30) + first_name = serializers.CharField(max_length=30) + last_name = serializers.CharField(max_length=30) + email = serializers.EmailField() + last_login = serializers.DateTimeField() + + def restore_object(self, attrs, instance=None): + """ + Given a dictionary of deserialized field values, either update + an existing model instance, or create a new model instance. + """ + if instance is not None: + instance.token = attrs.get('token', None) + instance.username = attrs.get('username', instance.username) + instance.first_name = attrs.get('first_name', instance.first_name) + instance.last_name = attrs.get('last_name', instance.last_name) + instance.email = attrs.get('email', instance.email) + instance.last_login = attrs.get('last_login', instance.last_login) + return instance + return UserLogged(**attrs) diff --git a/greenmine/base/urls.py b/greenmine/base/urls.py new file mode 100644 index 00000000..c810451b --- /dev/null +++ b/greenmine/base/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import patterns, url +from rest_framework.urlpatterns import format_suffix_patterns + +from greenmine.base.views import Login, Logout, ApiRoot + +urlpatterns = format_suffix_patterns(patterns('', + url(r'^auth/login/$', Login.as_view(), name='login'), + url(r'^auth/logout/$', Logout.as_view(), name='logout'), + url(r'^$', ApiRoot.as_view(), name='api_root'), +)) diff --git a/greenmine/base/views.py b/greenmine/base/views.py index 89ab07f2..13e79f99 100644 --- a/greenmine/base/views.py +++ b/greenmine/base/views.py @@ -1,97 +1,70 @@ # -*- coding: utf-8 -*- -import datetime -import json - -from django.core.serializers.json import DjangoJSONEncoder -from django.views.generic.base import View -from django.views.decorators.csrf import csrf_exempt from django.contrib.auth import logout, login, authenticate from django.contrib.auth.models import User -from django.utils.functional import Promise -from django.utils.encoding import force_text -from django.utils.decorators import method_decorator -from django.utils import timezone +from django.contrib.auth.views import login as auth_login, logout as auth_logout from django import http -from rest_framework.decorators import api_view -from rest_framework.response import Response +from rest_framework.renderers import JSONRenderer +from rest_framework.parsers import JSONParser from rest_framework.reverse import reverse +from rest_framework.views import APIView +from rest_framework.response import Response + +from greenmine.base.serializers import LoginSerializer, UserLogged -@api_view(('GET',)) -def api_root(request, format=None): - return Response({ - 'projects': reverse('project-list', request=request, format=format), - 'milestones': reverse('milestone-list', request=request, format=format), - 'user-stories': reverse('user-story-list', request=request, format=format), - 'changes': reverse('change-list', request=request, format=format), - 'change-attachments': reverse('change-attachment-list', request=request, format=format), - 'tasks': reverse('task-list', request=request, format=format), - 'severities': reverse('severity-list', request=request, format=format), - 'issue-status': reverse('issue-status-list', request=request, format=format), - 'task-status': reverse('task-status-list', request=request, format=format), - 'user-story-status': reverse('user-story-status-list', request=request, format=format), - 'priorities': reverse('priority-list', request=request, format=format), - 'issue-types': reverse('issue-type-list', request=request, format=format), - 'points': reverse('points-list', request=request, format=format), - }) +class ApiRoot(APIView): + def get(self, request, format=None): + return Response({ + 'login': reverse('login', request=request, format=format), + 'logout': reverse('logout', request=request, format=format), + 'projects': reverse('project-list', request=request, format=format), + 'milestones': reverse('milestone-list', request=request, format=format), + 'user-stories': reverse('user-story-list', request=request, format=format), + 'changes': reverse('change-list', request=request, format=format), + 'change-attachments': reverse('change-attachment-list', request=request, format=format), + 'tasks': reverse('task-list', request=request, format=format), + 'severities': reverse('severity-list', request=request, format=format), + 'issue-status': reverse('issue-status-list', request=request, format=format), + 'task-status': reverse('task-status-list', request=request, format=format), + 'user-story-status': reverse('user-story-status-list', request=request, format=format), + 'priorities': reverse('priority-list', request=request, format=format), + 'issue-types': reverse('issue-type-list', request=request, format=format), + 'points': reverse('points-list', request=request, format=format), + }) -class LazyEncoder(DjangoJSONEncoder): - """ - JSON encoder class for encode correctly traduction strings. - Is for ajax response encode. - """ - - def default(self, obj): - if isinstance(obj, Promise): - return force_text(obj) - elif isinstance(obj, datetime.datetime): - obj = timezone.localtime(obj) - return super(LazyEncoder, self).default(obj) - - -def request_json_to_dict(request): - try: - body = request.body.decode('utf-8') - return json.loads(body) - except Exception: - return {} - - -def to_json(data): - return json.dumps(data) - - -class Login(View): - def post(self, request): - data = request_json_to_dict(request) - - username = data.get('username', None) - password = data.get('password', None) +class Login(APIView): + def post(self, request, format=None): + username = request.DATA.get('username', None) + password = request.DATA.get('password', None) try: user = User.objects.get(username=username) if user.check_password(password): user = authenticate(username=username, password=password) login(request, user) - return http.HttpResponse(to_json({'token': request.session.session_key})) + + return_data = LoginSerializer(UserLogged(**{ + 'token': request.session.session_key, + 'username': request.user.username, + 'first_name': request.user.first_name, + 'last_name': request.user.last_name, + 'email': request.user.email, + 'last_login': request.user.last_login, + })) + + return http.HttpResponse(JSONRenderer().render(return_data.data), + content_type="application/json", + status=201) except User.DoesNotExist: pass return http.HttpResponseBadRequest() - @method_decorator(csrf_exempt) - def dispatch(self, *args, **kwargs): - return super(Login, self).dispatch(*args, **kwargs) - -class Logout(View): - def post(self, request): +class Logout(APIView): + def post(self, request, format=None): logout(request) return http.HttpResponse() - - @method_decorator(csrf_exempt) - def dispatch(self, *args, **kwargs): - return super(Login, self).dispatch(*args, **kwargs) diff --git a/greenmine/scrum/models.py b/greenmine/scrum/models.py index 052f4dc7..8ad3a48f 100644 --- a/greenmine/scrum/models.py +++ b/greenmine/scrum/models.py @@ -433,7 +433,6 @@ def project_post_save(sender, instance, created, **kwargs): Points.objects.create(project=instance, name=name, order=order) - # Email alerts signals handlers # TODO: temporary commented (Pending refactor) # from . import sigdispatch diff --git a/greenmine/urls.py b/greenmine/urls.py index 3b15be38..4fe5e8d0 100644 --- a/greenmine/urls.py +++ b/greenmine/urls.py @@ -3,12 +3,10 @@ from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() -from greenmine.base.views import Login, Logout +from greenmine.base.views import ApiRoot urlpatterns = patterns('', - url(r'^api/auth/login/$', Login.as_view(), name='api-login'), - url(r'^api/auth/logout/$', Logout.as_view(), name='api-logout'), - url(r'^api/$', 'greenmine.base.views.api_root'), + url(r'^api/', include('greenmine.base.urls')), url(r'^api/scrum/', include('greenmine.scrum.urls')), url(r'^admin/', include(admin.site.urls)), url(r'^grappelli/', include('grappelli.urls')),