Fixes on REST API

This commit is contained in:
Marc 2014-09-30 16:39:47 +00:00
parent 774422a41b
commit f984d28709
12 changed files with 37 additions and 35 deletions

View File

@ -131,7 +131,9 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* AccountAdminMixin auto adds 'account__name' on searchfields and handle account_link on fieldsets * AccountAdminMixin auto adds 'account__name' on searchfields and handle account_link on fieldsets
* Separate panel from server passwords? Store passwords on panel? * Separate panel from server passwords? Store passwords on panel? set_password special backend operation?
* be more explicit about which backends are resources and which are service handling
* What fields we really need on contacts? name email phone and what more? * What fields we really need on contacts? name email phone and what more?

View File

@ -22,18 +22,17 @@ class APIRoot(views.APIView):
singleton_pk = getattr(viewset, 'singleton_pk', False) singleton_pk = getattr(viewset, 'singleton_pk', False)
if singleton_pk: if singleton_pk:
url_name = detail_name.format(basename=basename) url_name = detail_name.format(basename=basename)
kwargs = { 'pk': singleton_pk(viewset(), request) } kwargs = {
'pk': singleton_pk(viewset(), request)
}
else: else:
url_name = list_name.format(basename=basename) url_name = list_name.format(basename=basename)
kwargs = {} kwargs = {}
url = reverse(url_name, request=request, format=format, kwargs=kwargs) url = reverse(url_name, request=request, format=format, kwargs=kwargs)
links.append('<%s>; rel="%s"' % (url, url_name)) links.append('<%s>; rel="%s"' % (url, url_name))
# Add user link headers = {
url_name = detail_name.format(basename='user') 'Link': ', '.join(links)
kwargs = { 'pk': request.user.pk } }
url = reverse(url_name, request=request, format=format, kwargs=kwargs)
links.append('<%s>; rel="%s"' % (url, url_name))
headers = { 'Link': ', '.join(links) }
body = { body = {
name.lower(): getattr(settings, name, None) for name in self.names name.lower(): getattr(settings, name, None) for name in self.names
} }

View File

@ -19,7 +19,7 @@ class AccountViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
qs = super(AccountViewSet, self).get_queryset() qs = super(AccountViewSet, self).get_queryset()
return qs.filter(id=self.request.user) return qs.filter(id=self.request.user.pk)
router.register(r'accounts', AccountViewSet) router.register(r'accounts', AccountViewSet)

View File

@ -62,8 +62,8 @@ class Account(auth.AbstractBaseUser):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
created = not self.pk created = not self.pk
super(Account, self).save(*args, **kwargs) super(Account, self).save(*args, **kwargs)
if created and hasattr(self, 'groups'): if created and hasattr(self, 'systemgroups'):
self.groups.create(name=self.username, account=self) self.systemgroups.create(name=self.username, account=self)
def send_email(self, template, context, contacts=[], attachments=[], html=None): def send_email(self, template, context, contacts=[], attachments=[], html=None):
contacts = self.contacts.filter(email_usages=contacts) contacts = self.contacts.filter(email_usages=contacts)

View File

@ -7,7 +7,7 @@ class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = Account model = Account
fields = ( fields = (
'url', 'username', 'type', 'language', 'register_date', 'is_active' 'url', 'username', 'type', 'language', 'date_joined', 'is_active'
) )

View File

@ -17,6 +17,6 @@ class BillSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeriali
class Meta: class Meta:
model = Bill model = Bill
fields = ( fields = (
'url', 'number', 'bill_type', 'status', 'created_on', 'due_on', 'url', 'number', 'type', 'total', 'is_sent', 'created_on', 'due_on',
'comments', 'html', 'lines' 'comments', 'html', 'lines'
) )

View File

@ -29,7 +29,7 @@ class TicketViewSet(viewsets.ModelViewSet):
qs = super(TicketViewSet, self).get_queryset() qs = super(TicketViewSet, self).get_queryset()
qs = qs.select_related('creator', 'queue') qs = qs.select_related('creator', 'queue')
qs = qs.prefetch_related('messages__author') qs = qs.prefetch_related('messages__author')
return qs.filter(creator__account=self.request.user.account_id) return qs.filter(creator=self.request.user)
class QueueViewSet(mixins.ListModelMixin, class QueueViewSet(mixins.ListModelMixin,

View File

@ -18,7 +18,7 @@ class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri
def get_fields(self, *args, **kwargs): def get_fields(self, *args, **kwargs):
fields = super(AddressSerializer, self).get_fields(*args, **kwargs) fields = super(AddressSerializer, self).get_fields(*args, **kwargs)
account = self.context['view'].request.user.account_id account = self.context['view'].request.user.pk
mailboxes = fields['mailboxes'].queryset mailboxes = fields['mailboxes'].queryset
fields['mailboxes'].queryset = mailboxes.filter(account=account) fields['mailboxes'].queryset = mailboxes.filter(account=account)
# TODO do it on permissions or in self.filter_by_account_field ? # TODO do it on permissions or in self.filter_by_account_field ?

View File

@ -6,13 +6,13 @@ from django.utils.translation import ugettext, ugettext_lazy as _
from orchestra.admin import ExtendedModelAdmin from orchestra.admin import ExtendedModelAdmin
from orchestra.admin.utils import wrap_admin_view from orchestra.admin.utils import wrap_admin_view
from orchestra.apps.accounts.admin import AccountAdminMixin from orchestra.apps.accounts.admin import SelectAccountAdminMixin
from .forms import UserCreationForm, UserChangeForm from .forms import UserCreationForm, UserChangeForm
from .models import SystemUser from .models import SystemUser
class SystemUserAdmin(AccountAdminMixin, ExtendedModelAdmin): class SystemUserAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
list_display = ('username', 'account_link', 'shell', 'home', 'is_active',) list_display = ('username', 'account_link', 'shell', 'home', 'is_active',)
list_filter = ('is_active', 'shell') list_filter = ('is_active', 'shell')
fieldsets = ( fieldsets = (
@ -32,7 +32,7 @@ class SystemUserAdmin(AccountAdminMixin, ExtendedModelAdmin):
}), }),
) )
search_fields = ['username'] search_fields = ['username']
readonly_fields = ('is_main', 'account_link',) readonly_fields = ('account_link',)
change_readonly_fields = ('username',) change_readonly_fields = ('username',)
filter_horizontal = ('groups',) filter_horizontal = ('groups',)
filter_by_account_fields = ('groups',) filter_by_account_fields = ('groups',)

View File

@ -1,15 +1,15 @@
from django.contrib.auth import get_user_model
from rest_framework import viewsets from rest_framework import viewsets
from orchestra.api import router, SetPasswordApiMixin from orchestra.api import router, SetPasswordApiMixin
from orchestra.apps.accounts.api import AccountApiMixin from orchestra.apps.accounts.api import AccountApiMixin
from .serializers import UserSerializer from .models import SystemUser
from .serializers import SystemUserSerializer
class UserViewSet(AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet): class SystemUserViewSet(AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet):
model = get_user_model() model = SystemUser
serializer_class = UserSerializer serializer_class = SystemUserSerializer
router.register(r'users', UserViewSet) router.register(r'systemusers', SystemUserViewSet)

View File

@ -29,10 +29,9 @@ class SystemUser(models.Model):
help_text=_("Home directory relative to account's ~main_user")) help_text=_("Home directory relative to account's ~main_user"))
shell = models.CharField(_("shell"), max_length=32, shell = models.CharField(_("shell"), max_length=32,
choices=settings.USERS_SHELLS, default=settings.USERS_DEFAULT_SHELL) choices=settings.USERS_SHELLS, default=settings.USERS_DEFAULT_SHELL)
groups = models.ManyToManyField('systemusers.Group', blank=True, groups = models.ManyToManyField('systemusers.SystemGroup', blank=True,
help_text=_("A new group will be created for the user. " help_text=_("A new group will be created for the user. "
"Which additional groups would you like them to be a member of?")) "Which additional groups would you like them to be a member of?"))
is_main = models.BooleanField(_("is main"), default=False)
is_active = models.BooleanField(_("active"), default=True, is_active = models.BooleanField(_("active"), default=True,
help_text=_("Designates whether this account should be treated as active. " help_text=_("Designates whether this account should be treated as active. "
"Unselect this instead of deleting accounts.")) "Unselect this instead of deleting accounts."))
@ -54,7 +53,7 @@ class SystemUser(models.Model):
created = not self.pk created = not self.pk
super(SystemUser, self).save(*args, **kwargs) super(SystemUser, self).save(*args, **kwargs)
if created: if created:
self.groups.get_or_create(name=self.username, account=self.account) self.groups.create(name=self.username, account=self.account)
def set_password(self, raw_password): def set_password(self, raw_password):
self.password = make_password(raw_password) self.password = make_password(raw_password)
@ -63,13 +62,13 @@ class SystemUser(models.Model):
return self.account.is_active and self.is_active return self.account.is_active and self.is_active
class Group(models.Model): class SystemGroup(models.Model):
name = models.CharField(_("name"), max_length=64, unique=True, name = models.CharField(_("name"), max_length=64, unique=True,
help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."), help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."),
validators=[validators.RegexValidator(r'^[\w.-]+$', validators=[validators.RegexValidator(r'^[\w.-]+$',
_("Enter a valid group name."), 'invalid')]) _("Enter a valid group name."), 'invalid')])
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
related_name='groups') related_name='systemgroups')
def __unicode__(self): def __unicode__(self):
return self.name return self.name

View File

@ -6,17 +6,19 @@ from rest_framework import serializers
from orchestra.apps.accounts.serializers import AccountSerializerMixin from orchestra.apps.accounts.serializers import AccountSerializerMixin
from orchestra.core.validators import validate_password from orchestra.core.validators import validate_password
from .models import SystemUser
class UserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
class SystemUserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
password = serializers.CharField(max_length=128, label=_('Password'), password = serializers.CharField(max_length=128, label=_('Password'),
validators=[validate_password], write_only=True, required=False, validators=[validate_password], write_only=True, required=False,
widget=widgets.PasswordInput) widget=widgets.PasswordInput)
groups = serializers.RelatedField(many=True)
class Meta: class Meta:
model = get_user_model() model = SystemUser
fields = ( fields = (
'url', 'username', 'password', 'first_name', 'last_name', 'email', 'url', 'username', 'password', 'home', 'shell', 'groups', 'is_active',
'is_admin', 'is_active',
) )
def validate_password(self, attrs, source): def validate_password(self, attrs, source):
@ -32,4 +34,4 @@ class UserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeriali
# FIXME this method will be called when saving nested serializers :( # FIXME this method will be called when saving nested serializers :(
if not obj.pk: if not obj.pk:
obj.set_password(obj.password) obj.set_password(obj.password)
super(UserSerializer, self).save_object(obj, **kwargs) super(SystemUserSerializer, self).save_object(obj, **kwargs)