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 -*- # -*- coding: utf-8 -*-
import uuid
from django.contrib.auth import logout, login, authenticate from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.views import login as auth_login, logout as auth_logout 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 django import http
from rest_framework.renderers import JSONRenderer from rest_framework.decorators import action
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 rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework import status from rest_framework import status, generics, viewsets
from rest_framework import generics from rest_framework import exceptions as excp
import django_filters
from haystack import query, inputs 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.serializers import SearchSerializer
from greenmine.base.models import User, Role from greenmine.base.models import User, Role
from greenmine.scrum import models from greenmine.scrum import models
from django.conf import settings
import django_filters
class ApiRoot(APIView): class RolesViewSet(viewsets.ViewSet):
def get(self, request, format=None): permission_classes = (IsAuthenticated,)
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
serializer_class = RoleSerializer 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,) permission_classes = (IsAuthenticated,)
def get_queryset(self): def get_list_queryset(self):
return self.model.objects.all() 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) project = self.request.QUERY_PARAMS.get('project', None)
if project is not 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)\ queryset = (User.objects.filter(projects__in=own_projects)
.order_by('id').distinct() .order_by('username').distinct())
def pre_save(self, obj): return queryset
pass
def list(self, request, pk=None):
queryset = self.get_list_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
class UserDetail(generics.RetrieveUpdateDestroyAPIView): def retrieve(self, request, pk=None):
model = User return Response({})
serializer_class = UserSerializer
permission_classes = (IsAuthenticated,)
import uuid @action(methods=["POST"], permission_classes=[])
from django.db.models import Q def login(self, request, pk=None):
from djmail.template_mail import MagicMailBuilder 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): if not user.check_password(password):
def post(self, request): 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) username_or_email = request.DATA.get('username', None)
if not username_or_email: if not username_or_email:
@ -126,63 +110,31 @@ class RecoveryPassword(APIView):
return Response({"detail": "Mail sended successful!"}) return Response({"detail": "Mail sended successful!"})
@action(methods=["GET", "POST"])
class Login(APIView): def logout(self, request, pk=None)
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):
logout(request) logout(request)
return Response() return Response()
class Search(APIView): class Search(viewsets.ViewSet):
def get(self, request, format=None): def list(self, request, **kwargs):
text = request.QUERY_PARAMS.get('text', None) text = request.QUERY_PARAMS.get('text', None)
project = request.QUERY_PARAMS.get('project', None) project_id = request.QUERY_PARAMS.get('project', None)
try:
project = self._get_project(project_id)
except models.Project.DoesNotExist:
raise excp.PermissionDenied({"detail": "Wrong project id"})
if text and project:
#TODO: permission check
queryset = query.SearchQuerySet() queryset = query.SearchQuerySet()
queryset = queryset.filter(text=inputs.AutoQuery(text)) queryset = queryset.filter(text=inputs.AutoQuery(text))
queryset = queryset.filter(project_id=project) queryset = queryset.filter(project_id=project_id)
return_data = SearchSerializer(queryset) return_data = SearchSerializer(queryset)
return Response(return_data.data) return Response(return_data.data)
return Response({"detail": "Parameter text can't be empty"}, status.HTTP_400_BAD_REQUEST) 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) request.session = engine.SessionStore(session_key)
COORS_ALLOWED_ORIGINS = getattr(settings, 'COORS_ALLOWED_ORIGINS', '*') COORS_ALLOWED_ORIGINS = getattr(settings, 'COORS_ALLOWED_ORIGINS', '*')
COORS_ALLOWED_METHODS = getattr(settings, 'COORS_ALLOWED_METHODS', COORS_ALLOWED_METHODS = getattr(settings, 'COORS_ALLOWED_METHODS',
['POST', 'GET', 'OPTIONS', 'PUT', 'DELETE', 'PATCH']) ['POST', 'GET', 'OPTIONS', 'PUT', 'DELETE', 'PATCH'])

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ from django.contrib import admin
admin.autodiscover() admin.autodiscover()
urlpatterns = patterns('', 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/scrum/', include('greenmine.scrum.urls')),
url(r'^api/documents/', include('greenmine.documents.urls')), url(r'^api/documents/', include('greenmine.documents.urls')),
url(r'^api/questions/', include('greenmine.questions.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-picklefield==0.3.0
django-reversion==1.7 django-reversion==1.7
django-sampledatahelper==0.0.1 django-sampledatahelper==0.0.1
djangorestframework==2.2.5 djangorestframework==2.3.6
gunicorn==17.5 gunicorn==17.5
kombu==2.5.12 kombu==2.5.12
mimeparse==0.1.3 mimeparse==0.1.3