Refactoring base views (update to new viewsets)

remotes/origin/enhancement/email-actions
Andrey Antukh 2013-07-22 23:33:30 +02:00
parent 9eb35a898a
commit a022085497
9 changed files with 103 additions and 277 deletions

View File

@ -1,111 +1,95 @@
# -*- coding: utf-8 -*-
import uuid
from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.views import login as auth_login, logout as auth_logout
from django.conf import settings
from django.db.models import Q
from django import http
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.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from rest_framework import generics
from rest_framework import status, generics, viewsets
from rest_framework import exceptions as excp
import django_filters
from haystack import query, inputs
from djmail.template_mail import MagicMailBuilder
from greenmine.base.serializers import (LoginSerializer, UserLogged,
UserSerializer, RoleSerializer)
from greenmine.base.serializers import LoginSerializer, UserLogged, UserSerializer, RoleSerializer
from greenmine.base.serializers import SearchSerializer
from greenmine.base.models import User, Role
from greenmine.scrum import models
from django.conf import settings
import django_filters
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),
'user-stories/statuses': reverse('user-story-status-list', request=request, format=format),
'user-stories/points': reverse('points-list', request=request, format=format),
'issues/attachments': reverse('issues-attachment-list', request=request, format=format),
'issues/statuses': reverse('issues-status-list', request=request, format=format),
'issues/types': reverse('issues-type-list', request=request, format=format),
'issues': reverse('issues-list', request=request, format=format),
'tasks': reverse('tasks-list', request=request, format=format),
'tasks/statuses': reverse('tasks-status-list', request=request, format=format),
'tasks/attachments': reverse('tasks-attachment-list', request=request, format=format),
'severities': reverse('severity-list', request=request, format=format),
'priorities': reverse('priority-list', request=request, format=format),
'documents': reverse('document-list', request=request, format=format),
'questions': reverse('question-list', request=request, format=format),
'wiki/pages': reverse('wiki-page-list', request=request, format=format),
'users': reverse('user-list', request=request, format=format),
'roles': reverse('user-roles', request=request, format=format),
'search': reverse('search', request=request, format=format),
})
class RoleList(generics.ListCreateAPIView):
model = Role
class RolesViewSet(viewsets.ViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = RoleSerializer
def list(self, request, pk=None):
queryset = Role.objects.all()
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
role = Role.objects.get(pk=pk)
serializer = self.serializer_class(role)
return Response(serializer.data)
class UsersViewSet(viewsets.ViewSet):
permission_classes = (IsAuthenticated,)
def get_queryset(self):
return self.model.objects.all()
def get_list_queryset(self):
own_projects = (models.Project.objects
.filter(members=self.request.user))
class RoleDetail(generics.RetrieveAPIView):
model = Role
serializer_class = RoleSerializer
permission_classes = (IsAuthenticated,)
class UserFilter(django_filters.FilterSet):
class Meta:
model = User
fields = ['is_active']
class UserList(generics.ListCreateAPIView):
model = User
serializer_class = UserSerializer
filter_class = UserFilter
permission_classes = (IsAuthenticated,)
def get_queryset(self):
projects = models.Project.objects.filter(members=self.request.user)
#Project filtering
project = self.request.QUERY_PARAMS.get('project', None)
if project is not None:
projects = projects.filter(id=project)
own_projects = own_projects.filter(pk=project)
return super(UserList, self).get_queryset().filter(projects__in=projects)\
.order_by('id').distinct()
queryset = (User.objects.filter(projects__in=own_projects)
.order_by('username').distinct())
def pre_save(self, obj):
pass
return queryset
def list(self, request, pk=None):
queryset = self.get_list_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
model = User
serializer_class = UserSerializer
permission_classes = (IsAuthenticated,)
def retrieve(self, request, pk=None):
return Response({})
import uuid
from django.db.models import Q
from djmail.template_mail import MagicMailBuilder
@action(methods=["POST"], permission_classes=[])
def login(self, request, pk=None):
username = request.DATA.get('username', None)
password = request.DATA.get('password', None)
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return Response({"detail": "Invalid username or password"},
status.HTTP_400_BAD_REQUEST)
class RecoveryPassword(APIView):
def post(self, request):
if not user.check_password(password):
return Response({"detail": "Invalid username or password"},
status.HTTP_400_BAD_REQUEST)
user = authenticate(username=username, password=password)
login(request, user)
serializer = UserSerializer(user)
response_data = serializer.data
response_data["token"] = request.session.session_key
return Response(response_data)
@action(methods=["POST"], permission_classes=[])
def password_recovery(self, request, pk=None):
username_or_email = request.DATA.get('username', None)
if not username_or_email:
@ -126,63 +110,31 @@ class RecoveryPassword(APIView):
return Response({"detail": "Mail sended successful!"})
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_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,
'color': request.user.color,
'description': request.user.description,
'default_language': request.user.default_language,
'default_timezone': request.user.default_timezone,
'colorize_tags': request.user.colorize_tags,
}))
return Response(return_data.data)
except User.DoesNotExist:
pass
return Response({"detail": "Invalid username or password"}, status.HTTP_400_BAD_REQUEST)
class Logout(APIView):
def post(self, request, format=None):
@action(methods=["GET", "POST"])
def logout(self, request, pk=None)
logout(request)
return Response()
class Search(APIView):
def get(self, request, format=None):
class Search(viewsets.ViewSet):
def list(self, request, **kwargs):
text = request.QUERY_PARAMS.get('text', None)
project = request.QUERY_PARAMS.get('project', None)
project_id = request.QUERY_PARAMS.get('project', None)
if text and project:
#TODO: permission check
queryset = query.SearchQuerySet()
queryset = queryset.filter(text=inputs.AutoQuery(text))
queryset = queryset.filter(project_id=project)
return_data = SearchSerializer(queryset)
return Response(return_data.data)
return Response({"detail": "Parameter text can't be empty"}, status.HTTP_400_BAD_REQUEST)
try:
project = self._get_project(project_id)
except models.Project.DoesNotExist:
raise excp.PermissionDenied({"detail": "Wrong project id"})
queryset = query.SearchQuerySet()
queryset = queryset.filter(text=inputs.AutoQuery(text))
queryset = queryset.filter(project_id=project_id)
return_data = SearchSerializer(queryset)
return Response(return_data.data)
def _get_project(self, project_id):
own_projects = (models.Project.objects
.filter(members=self.request.user))
return own_projects.get(pk=project_id)

View File

@ -1,133 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2011 Andrei Antoukh <niwi@niwi.be>
# License: BSD-3
from django.db import models
from base64 import b64encode, b64decode
try:
import cPickle as pickle
except ImportError:
import pickle
import logging
logger = logging.getLogger("niwi")
class DictField(models.Field):
""" Dictionary pickled field. """
__metaclass__ = models.SubfieldBase
__prefix__ = "pickle_dict::"
__pickleproto__ = -1
def to_python(self, value):
if isinstance(value, dict):
return value
if isinstance(value, (str, unicode)) and value.startswith(self.__prefix__):
local_value = value[len(self.__prefix__):]
return pickle.loads(b64decode(str(local_value)))
else:
return {}
def get_db_prep_value(self, value, connection, prepared=False):
if value is not None:
if isinstance(value, dict):
value = self.__prefix__ + b64encode(pickle.dumps(value, protocol=self.__pickleproto__))
else:
raise TypeError('This field can only store dictionaries.')
return value
def get_internal_type(self):
return 'TextField'
def value_to_string(self, obj):
if not obj:
return ""
value = getattr(obj, self.attname)
assert isinstance(value, dict)
return self.__prefix__ + b64encode(pickle.dumps(value, protocol=self.__pickleproto__))
return self.token.join(map(unicode, value))
def south_field_triple(self):
from south.modelsinspector import introspector
field_class = "django.db.models.fields.TextField"
args, kwargs = introspector(self)
return (field_class, args, kwargs)
class ListField(models.Field):
""" Pickled list field. """
__metaclass__ = models.SubfieldBase
__prefix__ = "pickle_list::"
__pickleproto__ = -1
def to_python(self, value):
if isinstance(value, (list, tuple)):
return value
if isinstance(value, (str, unicode)) and value.startswith(self.__prefix__):
local_value = value[len(self.__prefix__):]
return pickle.loads(b64decode(str(local_value)))
else:
return []
def get_db_prep_value(self, value, connection, prepared=False):
if value is not None:
if isinstance(value, (list, tuple)):
value = self.__prefix__ + b64encode(pickle.dumps(value, protocol=self.__pickleproto__))
else:
raise TypeError('This field can only store list or tuple objects')
return value
def get_internal_type(self):
return 'TextField'
def value_to_string(self, obj):
if not obj:
return ""
value = getattr(obj, self.attname)
assert isinstance(value, (list, tuple))
return self.__prefix__ + b64encode(pickle.dumps(value, protocol=self.__pickleproto__))
return self.token.join(map(unicode, value))
def south_field_triple(self):
from south.modelsinspector import introspector
field_class = "django.db.models.fields.TextField"
args, kwargs = introspector(self)
return (field_class, args, kwargs)
class CSVField(models.TextField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
self.token = kwargs.pop('token', ',')
super(CSVField, self).__init__(*args, **kwargs)
def to_python(self, value):
if not value:
return
if isinstance(value, list):
return value
return value.split(self.token)
def get_db_prep_value(self, value):
if not value:
return
assert(isinstance(value, list) or isinstance(value, tuple))
return self.token.join([unicode(s) for s in value])
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)
def south_field_triple(self):
from south.modelsinspector import introspector
field_class = "django.db.models.fields.TextField"
args, kwargs = introspector(self)
return (field_class, args, kwargs)

View File

@ -18,6 +18,7 @@ class GreenmineSessionMiddleware(SessionMiddleware):
request.session = engine.SessionStore(session_key)
COORS_ALLOWED_ORIGINS = getattr(settings, 'COORS_ALLOWED_ORIGINS', '*')
COORS_ALLOWED_METHODS = getattr(settings, 'COORS_ALLOWED_METHODS',
['POST', 'GET', 'OPTIONS', 'PUT', 'DELETE', 'PATCH'])

View File

@ -47,6 +47,9 @@ class User(WatcherMixin, AbstractUser):
verbose_name=_('colorize tags'))
objects = UserManager()
class Meta:
ordering = ["username"]
class Role(models.Model):
name = models.CharField(max_length=200, null=False, blank=False,

View File

@ -1,17 +1,21 @@
# -*- coding: utf-8 -*-
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework import routers
from django.conf.urls import patterns, url
from greenmine.base import api
# Special router for actions.
actions_router = routers.Route(url=r'^{prefix}/actions/{methodname}{trailing_slash}$',
mapping={'{httpmethod}': '{methodname}'},
name='{basename}-{methodnamehyphen}',
initkwargs={})
urlpatterns = format_suffix_patterns(patterns('',
url(r'^auth/login/$', api.Login.as_view(), name='login'),
url(r'^auth/logout/$', api.Logout.as_view(), name='logout'),
url(r'^users/$', api.UserList.as_view(), name="user-list"),
url(r'^users/(?P<pk>[0-9]+)/$', api.UserDetail.as_view(), name="user-detail"),
url(r'^roles/$', api.RoleList.as_view(), name="roles"),
url(r'^roles/(?P<pk>[0-9]+)/$', api.RoleDetail.as_view(), name='role-detail'),
url(r'^search/$', api.Search.as_view(), name="search"),
url(r'^$', api.ApiRoot.as_view(), name='api_root'),
))
router = routers.DefaultRouter(trailing_slash=False)
router.routes.append(actions_router)
router.register("users", api.UsersViewSet, base_name="users")
router.register("roles", api.RolesViewSet, base_name="roles")
router.register("search", api.Search, base_name="search")
urlpatterns = router.urls

View File

@ -3,8 +3,8 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from picklefield.fields import PickledObjectField
from greenmine.base.utils.slug import slugify_uniquely as slugify
from greenmine.base.fields import DictField
class Document(models.Model):
@ -27,7 +27,7 @@ class Document(models.Model):
attached_file = models.FileField(max_length=1000, null=True, blank=True,
upload_to='documents',
verbose_name=_('attached_file'))
tags = DictField(null=False, blank=True,
tags = PickledObjectField(null=False, blank=True,
verbose_name=_('tags'))
class Meta:

View File

@ -6,7 +6,6 @@ from django.utils import timezone
from django.dispatch import receiver
from greenmine.base.utils.slug import slugify_uniquely, ref_uniquely
from greenmine.base.fields import DictField
from greenmine.scrum.models import Project
from picklefield.fields import PickledObjectField

View File

@ -6,7 +6,7 @@ from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^api/', include('greenmine.base.urls')),
url(r'^api/core/', include('greenmine.base.urls')),
url(r'^api/scrum/', include('greenmine.scrum.urls')),
url(r'^api/documents/', include('greenmine.documents.urls')),
url(r'^api/questions/', include('greenmine.questions.urls')),

View File

@ -16,7 +16,7 @@ git+git://github.com/toastdriven/django-haystack.git
django-picklefield==0.3.0
django-reversion==1.7
django-sampledatahelper==0.0.1
djangorestframework==2.2.5
djangorestframework==2.3.6
gunicorn==17.5
kombu==2.5.12
mimeparse==0.1.3