From f984d28709402343ab25f55208c103a9f8ae01b8 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 30 Sep 2014 16:39:47 +0000 Subject: [PATCH] Fixes on REST API --- TODO.md | 4 +++- orchestra/api/root.py | 13 ++++++------- orchestra/apps/accounts/api.py | 2 +- orchestra/apps/accounts/models.py | 4 ++-- orchestra/apps/accounts/serializers.py | 2 +- orchestra/apps/bills/serializers.py | 2 +- orchestra/apps/issues/api.py | 2 +- orchestra/apps/mails/serializers.py | 4 ++-- orchestra/apps/systemusers/admin.py | 6 +++--- orchestra/apps/systemusers/api.py | 12 ++++++------ orchestra/apps/systemusers/models.py | 9 ++++----- orchestra/apps/systemusers/serializers.py | 12 +++++++----- 12 files changed, 37 insertions(+), 35 deletions(-) diff --git a/TODO.md b/TODO.md index a029f385..8204d87c 100644 --- a/TODO.md +++ b/TODO.md @@ -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 -* 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? diff --git a/orchestra/api/root.py b/orchestra/api/root.py index 4a7121b8..19ada57e 100644 --- a/orchestra/api/root.py +++ b/orchestra/api/root.py @@ -22,18 +22,17 @@ class APIRoot(views.APIView): singleton_pk = getattr(viewset, 'singleton_pk', False) if singleton_pk: url_name = detail_name.format(basename=basename) - kwargs = { 'pk': singleton_pk(viewset(), request) } + kwargs = { + 'pk': singleton_pk(viewset(), request) + } else: url_name = list_name.format(basename=basename) kwargs = {} url = reverse(url_name, request=request, format=format, kwargs=kwargs) links.append('<%s>; rel="%s"' % (url, url_name)) - # Add user link - url_name = detail_name.format(basename='user') - 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) } + headers = { + 'Link': ', '.join(links) + } body = { name.lower(): getattr(settings, name, None) for name in self.names } diff --git a/orchestra/apps/accounts/api.py b/orchestra/apps/accounts/api.py index 7165be20..d9479b0b 100644 --- a/orchestra/apps/accounts/api.py +++ b/orchestra/apps/accounts/api.py @@ -19,7 +19,7 @@ class AccountViewSet(viewsets.ModelViewSet): def get_queryset(self): 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) diff --git a/orchestra/apps/accounts/models.py b/orchestra/apps/accounts/models.py index 627ea5d2..08e311c9 100644 --- a/orchestra/apps/accounts/models.py +++ b/orchestra/apps/accounts/models.py @@ -62,8 +62,8 @@ class Account(auth.AbstractBaseUser): def save(self, *args, **kwargs): created = not self.pk super(Account, self).save(*args, **kwargs) - if created and hasattr(self, 'groups'): - self.groups.create(name=self.username, account=self) + if created and hasattr(self, 'systemgroups'): + self.systemgroups.create(name=self.username, account=self) def send_email(self, template, context, contacts=[], attachments=[], html=None): contacts = self.contacts.filter(email_usages=contacts) diff --git a/orchestra/apps/accounts/serializers.py b/orchestra/apps/accounts/serializers.py index 01256647..45bbfea9 100644 --- a/orchestra/apps/accounts/serializers.py +++ b/orchestra/apps/accounts/serializers.py @@ -7,7 +7,7 @@ class AccountSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Account fields = ( - 'url', 'username', 'type', 'language', 'register_date', 'is_active' + 'url', 'username', 'type', 'language', 'date_joined', 'is_active' ) diff --git a/orchestra/apps/bills/serializers.py b/orchestra/apps/bills/serializers.py index 9d747722..0c15ebde 100644 --- a/orchestra/apps/bills/serializers.py +++ b/orchestra/apps/bills/serializers.py @@ -17,6 +17,6 @@ class BillSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeriali class Meta: model = Bill fields = ( - 'url', 'number', 'bill_type', 'status', 'created_on', 'due_on', + 'url', 'number', 'type', 'total', 'is_sent', 'created_on', 'due_on', 'comments', 'html', 'lines' ) diff --git a/orchestra/apps/issues/api.py b/orchestra/apps/issues/api.py index aa811c3f..11d58a27 100644 --- a/orchestra/apps/issues/api.py +++ b/orchestra/apps/issues/api.py @@ -29,7 +29,7 @@ class TicketViewSet(viewsets.ModelViewSet): qs = super(TicketViewSet, self).get_queryset() qs = qs.select_related('creator', 'queue') 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, diff --git a/orchestra/apps/mails/serializers.py b/orchestra/apps/mails/serializers.py index 7dfe3e34..c7516de7 100644 --- a/orchestra/apps/mails/serializers.py +++ b/orchestra/apps/mails/serializers.py @@ -18,10 +18,10 @@ class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri def get_fields(self, *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 fields['mailboxes'].queryset = mailboxes.filter(account=account) # TODO do it on permissions or in self.filter_by_account_field ? domain = fields['domain'].queryset - fields['domain'].queryset = domain .filter(account=account) + fields['domain'].queryset = domain.filter(account=account) return fields diff --git a/orchestra/apps/systemusers/admin.py b/orchestra/apps/systemusers/admin.py index 0abe1cd3..e12dc16f 100644 --- a/orchestra/apps/systemusers/admin.py +++ b/orchestra/apps/systemusers/admin.py @@ -6,13 +6,13 @@ from django.utils.translation import ugettext, ugettext_lazy as _ from orchestra.admin import ExtendedModelAdmin 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 .models import SystemUser -class SystemUserAdmin(AccountAdminMixin, ExtendedModelAdmin): +class SystemUserAdmin(SelectAccountAdminMixin, ExtendedModelAdmin): list_display = ('username', 'account_link', 'shell', 'home', 'is_active',) list_filter = ('is_active', 'shell') fieldsets = ( @@ -32,7 +32,7 @@ class SystemUserAdmin(AccountAdminMixin, ExtendedModelAdmin): }), ) search_fields = ['username'] - readonly_fields = ('is_main', 'account_link',) + readonly_fields = ('account_link',) change_readonly_fields = ('username',) filter_horizontal = ('groups',) filter_by_account_fields = ('groups',) diff --git a/orchestra/apps/systemusers/api.py b/orchestra/apps/systemusers/api.py index c62c7e18..7ffd357f 100644 --- a/orchestra/apps/systemusers/api.py +++ b/orchestra/apps/systemusers/api.py @@ -1,15 +1,15 @@ -from django.contrib.auth import get_user_model from rest_framework import viewsets from orchestra.api import router, SetPasswordApiMixin 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): - model = get_user_model() - serializer_class = UserSerializer +class SystemUserViewSet(AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet): + model = SystemUser + serializer_class = SystemUserSerializer -router.register(r'users', UserViewSet) +router.register(r'systemusers', SystemUserViewSet) diff --git a/orchestra/apps/systemusers/models.py b/orchestra/apps/systemusers/models.py index bf950a78..6120e2b7 100644 --- a/orchestra/apps/systemusers/models.py +++ b/orchestra/apps/systemusers/models.py @@ -29,10 +29,9 @@ class SystemUser(models.Model): help_text=_("Home directory relative to account's ~main_user")) shell = models.CharField(_("shell"), max_length=32, 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. " "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, help_text=_("Designates whether this account should be treated as active. " "Unselect this instead of deleting accounts.")) @@ -54,7 +53,7 @@ class SystemUser(models.Model): created = not self.pk super(SystemUser, self).save(*args, **kwargs) 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): self.password = make_password(raw_password) @@ -63,13 +62,13 @@ class SystemUser(models.Model): 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, help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."), validators=[validators.RegexValidator(r'^[\w.-]+$', _("Enter a valid group name."), 'invalid')]) account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), - related_name='groups') + related_name='systemgroups') def __unicode__(self): return self.name diff --git a/orchestra/apps/systemusers/serializers.py b/orchestra/apps/systemusers/serializers.py index 321e8b02..b3177033 100644 --- a/orchestra/apps/systemusers/serializers.py +++ b/orchestra/apps/systemusers/serializers.py @@ -6,17 +6,19 @@ from rest_framework import serializers from orchestra.apps.accounts.serializers import AccountSerializerMixin 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'), validators=[validate_password], write_only=True, required=False, widget=widgets.PasswordInput) + groups = serializers.RelatedField(many=True) class Meta: - model = get_user_model() + model = SystemUser fields = ( - 'url', 'username', 'password', 'first_name', 'last_name', 'email', - 'is_admin', 'is_active', + 'url', 'username', 'password', 'home', 'shell', 'groups', 'is_active', ) 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 :( if not obj.pk: obj.set_password(obj.password) - super(UserSerializer, self).save_object(obj, **kwargs) + super(SystemUserSerializer, self).save_object(obj, **kwargs)