Skip to content
This repository has been archived by the owner on Jun 29, 2020. It is now read-only.

Commit

Permalink
Merge pull request #54 from kawazrepos/new_api_interface
Browse files Browse the repository at this point in the history
Refactoring for adding new API interface
  • Loading branch information
giginet committed May 28, 2014
2 parents 562eee7 + 810da7e commit 48ce16b
Show file tree
Hide file tree
Showing 48 changed files with 572 additions and 420 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pyyaml
pillow
markdown
django-tastypie
djangorestframework
django-permission>=0.7.1
django-markupfield
django-thumbnailfield>=0.2.0
Expand Down
17 changes: 17 additions & 0 deletions src/kawaz/api/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# coding=utf-8
"""
"""
__author__ = 'Alisue <lambdalisue@hashnote.net>'
from rest_framework import filters
from kawaz.core.utils.permission import filter_with_perm


class KawazObjectPermissionFilter(filters.BaseFilterBackend):
"""
A filter backend that limits results to those where the requesting user
has read object level permissions.
"""
def filter_queryset(self, request, queryset, view):
user = request.user
queryset = filter_with_perm(user, queryset, 'view')
return queryset
5 changes: 5 additions & 0 deletions src/kawaz/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# coding=utf-8
"""
"""
__author__ = 'Alisue <lambdalisue@hashnote.net>'

33 changes: 33 additions & 0 deletions src/kawaz/api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding=utf-8
"""
"""
__author__ = 'Alisue <lambdalisue@hashnote.net>'
from rest_framework import viewsets
from .filters import KawazObjectPermissionFilter


class KawazModelViewSet(viewsets.ModelViewSet):
author_field_name = None

def pre_save(self, obj):
if self.author_field_name and self.request.user.is_authenticated():
obj[self.author_field_name] = self.request.user

def get_queryset(self):
manager = self.model.objects
if self.request.method == 'GET':
return self.get_queryset_for_read(manager)
return self.get_queryset_for_write(manager)

def get_queryset_for_read(self, manager):
if hasattr(manager, 'published'):
return manager.published(self.request.user)
return manager.all()

def get_queryset_for_write(self, manager):
if hasattr(manager, 'related'):
return manager.related(self.request.user)
return manager.all()

def get_filter_backends(self):
return (KawazObjectPermissionFilter,)
13 changes: 7 additions & 6 deletions src/kawaz/apps/announcements/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext as _
from markupfield.fields import MarkupField
from kawaz.core.permissions.logics import PUB_STATES
from kawaz.core.publishments.models import PublishmentManagerMixin
from kawaz.core.publishments.models import PUB_STATES


class AnnouncementManager(models.Manager):
class AnnouncementManager(models.Manager, PublishmentManagerMixin):
def published(self, user):
"""
指定されたユーザーに対して公開されているAnnouncementインスタンスを含む
Expand All @@ -27,7 +27,7 @@ def published(self, user):
"""
q = Q(pub_state='public')
if user and user.is_authenticated():
if user.role in ['seele', 'nerv', 'children']:
if user.is_member:
# Seele, Nerv, Children can see the protected announcement
q |= Q(pub_state='protected')
return self.filter(q)
Expand Down Expand Up @@ -57,8 +57,9 @@ class Announcement(models.Model):
"""

# 必須フィールド
pub_state = models.CharField(_('Publish status'),
max_length=10, choices=PUB_STATES)
pub_state = models.CharField(_("Publish status"),
max_length=10, choices=PUB_STATES,
default="public")
title = models.CharField(_('Title'), max_length=128)
body = MarkupField(_('Body'), default_markup_type='markdown')
silently = models.BooleanField(_('Silently'), default=False,
Expand Down
42 changes: 11 additions & 31 deletions src/kawaz/apps/blogs/models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import datetime
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError

from markupfield.fields import MarkupField

from kawaz.core.db.decorators import validate_on_save
from kawaz.core.permissions.logics import PUB_STATES
from kawaz.core.publishments.models import PUB_STATES
from kawaz.core.publishments.models import PublishmentManagerMixin


class Category(models.Model):
Expand All @@ -24,44 +21,27 @@ class Category(models.Model):
verbose_name=_('Author'),
related_name='blog_categories',
editable=False)

class Meta:
# カテゴリはユーザーが所有するものなので unique together を指定
unique_together = (('author', 'label'),)
unique_together = (('author', 'label'),)

def __str__(self):
return "{}({})".format(self.label, self.author.username)


class EntryManager(models.Manager):
def published(self, user):
"""
指定されたユーザが閲覧可能な記事を含むクエリを返す
ユーザーがメンバーだった場合は全体・内部公開記事、それ以外の場合は
内部公開記事のみを含むクエリを返す
"""
q = Q(pub_state='public')
if user and user.is_authenticated() and user.is_member:
q |= Q(pub_state='protected')
return self.filter(q).distinct()

def draft(self, user):
"""
指定されたユーザが所有する下書き記事を含むクエリを返す
"""
if user and user.is_authenticated() and user.is_member:
return self.filter(author=user, pub_state='draft')
return self.none()
class EntryManager(models.Manager, PublishmentManagerMixin):
pass


@validate_on_save
class Entry(models.Model):
"""
ブログ記事モデル
"""
pub_state = models.CharField(_('Publish status'), max_length=10,
choices=PUB_STATES, default="public")
pub_state = models.CharField(_("Publish status"),
max_length=10, choices=PUB_STATES,
default="public")
title = models.CharField(_('Title'), max_length=255)
body = MarkupField(_('Body'), default_markup_type='markdown')
category = models.ForeignKey(Category, verbose_name=_('Category'),
Expand Down Expand Up @@ -127,10 +107,10 @@ def get_absolute_url(self):

from permission import add_permission_logic
from permission.logics.author import AuthorPermissionLogic
from kawaz.core.permissions.logics import PubStatePermissionLogic
from kawaz.core.publishments.perms import PublishmentPermissionLogic

add_permission_logic(Entry, AuthorPermissionLogic(
field_name='author',
any_permission=True,
))
add_permission_logic(Entry, PubStatePermissionLogic())
add_permission_logic(Entry, PublishmentPermissionLogic())
72 changes: 28 additions & 44 deletions src/kawaz/apps/events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
from django.db import models
from django.db.models import Q, F, Count
from django.utils.translation import ugettext as _
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.core.exceptions import PermissionDenied
from markupfield.fields import MarkupField

from kawaz.core.db.decorators import validate_on_save
from kawaz.core.permissions.logics import PUB_STATES
from kawaz.core.publishments.models import PUB_STATES
from kawaz.core.publishments.models import PublishmentManagerMixin


class EventManager(models.Manager, PublishmentManagerMixin):
author_field_name = 'organizer'

class EventManager(models.Manager):
def active(self, user):
"""
指定されたユーザーに公開されたイベントの中で、まだ終わっていない
Expand All @@ -36,26 +37,6 @@ def attendable(self, user):
q2 = (Q(number_restriction__gt=F('attendees_count')) |
Q(number_restriction=None))
return qs.annotate(attendees_count=Count('attendees')).filter(q1 & q2)

def published(self, user):
"""
指定されたユーザーに公開されたイベントを含むクエリを返す
メンバーは全体および内部公開イベント、その他は全体公開イベントのみ
を含むクエリを返す
"""
q = Q(pub_state='public')
if user and user.is_authenticated() and user.is_member:
q |= Q(pub_state='protected')
return self.filter(q)

def draft(self, user):
"""
指定されたユーザが所有する下書きイベントを含むクエリを返す
"""
if user and user.is_authenticated():
return self.filter(organizer=user, pub_state='draft')
return self.none()


@validate_on_save
Expand All @@ -73,13 +54,15 @@ class Event(models.Model):
period_end = models.DateTimeField(_("End time"),
blank=True, null=True)
place = models.CharField(_("Place"), max_length=255, blank=True)
number_restriction = models.PositiveIntegerField(_('Number restriction'),
default=None, blank=True, null=True,
help_text=_("Use this to limit the number of attendees."))
attendance_deadline = models.DateTimeField(_('Attendance deadline'),
default=None, blank=True, null=True,
help_text=_("A deadline of the attendance. "
"No member can attend the event after this deadline."))
number_restriction = models.PositiveIntegerField(
_('Number restriction'),
default=None, blank=True, null=True,
help_text=_("Use this to limit the number of attendees."))
attendance_deadline = models.DateTimeField(
_('Attendance deadline'),
default=None, blank=True, null=True,
help_text=_("A deadline of the attendance. "
"No member can attend the event after this deadline."))
# 編集不可フィールド
organizer = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name=_("Organizer"),
Expand All @@ -93,12 +76,12 @@ class Event(models.Model):
updated_at = models.DateTimeField(_("Modified at"), auto_now=True)

objects = EventManager()

class Meta:
ordering = (
'period_start', 'period_end',
'-created_at', '-updated_at',
'title', '-pk')
'period_start', 'period_end',
'-created_at', '-updated_at',
'title', '-pk')
verbose_name = _("Event")
verbose_name_plural = _("Events")
permissions = (
Expand All @@ -124,10 +107,10 @@ def clean(self):
if self.period_start and self.period_end:
if self.period_start > self.period_end:
raise ValidationError(
_('End time must be later than start time.'))
elif (self.period_start < datetime.datetime.now() and
(not self.pk or
Event.objects.filter(pk=self.pk).count() == 0)):
_('End time must be later than start time.'))
elif (self.period_start < datetime.datetime.now() and
(not self.pk or
Event.objects.filter(pk=self.pk).count() == 0)):
raise ValidationError(_('Start time must be future.'))
elif (self.period_end - self.period_start).days > 7:
raise ValidationError(_('The period of event is too long.'))
Expand All @@ -136,9 +119,9 @@ def clean(self):
if self.number_restriction is not None and self.number_restriction < 1:
raise ValidationError(
_("Number restriction should be grater than 0"))
if (self.attendance_deadline and
self.attendance_deadline < datetime.datetime.now() and
(not self.pk or
if (self.attendance_deadline and
self.attendance_deadline < datetime.datetime.now() and
(not self.pk or
Event.objects.filter(pk=self.pk).count() == 0)):
raise ValidationError(_('Attendance deadline must be future.'))

Expand Down Expand Up @@ -190,6 +173,7 @@ def get_absolute_url(self):
from django.db.models.signals import post_save
from django.dispatch import receiver


@receiver(post_save, sender=Event)
def join_organizer(**kwargs):
"""
Expand All @@ -203,7 +187,7 @@ def join_organizer(**kwargs):

from permission import add_permission_logic
from .perms import EventPermissionLogic
from .perms import PubStatePermissionLogic
from kawaz.core.publishments.perms import PublishmentPermissionLogic
add_permission_logic(Event, EventPermissionLogic()),
add_permission_logic(Event, PubStatePermissionLogic(
add_permission_logic(Event, PublishmentPermissionLogic(
author_field_name='organizer')),
2 changes: 1 addition & 1 deletion src/kawaz/apps/events/perms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"""
__author__ = 'Alisue <lambdalisue@hashnote.net>'
from permission.logics import PermissionLogic
from kawaz.core.permissions.logics import PubStatePermissionLogic


class EventPermissionLogic(PermissionLogic):
Expand Down Expand Up @@ -66,6 +65,7 @@ def has_perm(self, user_obj, perm, obj=None):
# generally
return True
return False

# macros
def author_required(user_obj, perm, obj):
if user_obj.role not in ('seele', 'nerv', 'children'):
Expand Down

0 comments on commit 48ce16b

Please sign in to comment.