Added postonly serializer fields
This commit is contained in:
parent
b93ba235b0
commit
d817fe7198
12
TODO.md
12
TODO.md
|
@ -135,19 +135,15 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
|||
* multiple domains creation; line separated domains
|
||||
* Move MU webapps to SaaS?
|
||||
|
||||
* DN: Transaction atomicity and backend failure
|
||||
|
||||
* SaaS Icons
|
||||
|
||||
* offer to create mailbox on account creation
|
||||
|
||||
* init.d celery scripts
|
||||
-# Required-Start: $network $local_fs $remote_fs postgresql celeryd
|
||||
-# Required-Stop: $network $local_fs $remote_fs postgresql celeryd
|
||||
|
||||
|
||||
* POST only fields (account, username, name) etc
|
||||
|
||||
* POST only fields (account, username, name) etc http://inka-labs.com/blog/2013/04/18/post-only-fields-django-rest-framework/
|
||||
* for list virtual_domains cleaning up we need to know the old domain name when a list changes its address domain, but this is not possible with the current design.
|
||||
|
||||
* regenerate virtual_domains every time (configure a separate file for orchestra on postfix)
|
||||
* update_fields=[] doesn't trigger post save!
|
||||
|
||||
* lists -> SaaS ?
|
||||
|
|
|
@ -235,7 +235,7 @@ class ChangePasswordAdminMixin(object):
|
|||
def change_password(self, request, id, form_url=''):
|
||||
if not self.has_change_permission(request):
|
||||
raise PermissionDenied
|
||||
# TODO use this insetad of self.get_object()
|
||||
# TODO use this insetad of self.get_object(), in other places
|
||||
user = get_object_or_404(self.get_queryset(request), pk=id)
|
||||
|
||||
related = []
|
||||
|
|
|
@ -10,6 +10,55 @@ class SetPasswordSerializer(serializers.Serializer):
|
|||
widget=widgets.PasswordInput, validators=[validate_password])
|
||||
|
||||
|
||||
|
||||
from rest_framework.serializers import (HyperlinkedModelSerializerOptions,
|
||||
HyperlinkedModelSerializer)
|
||||
|
||||
|
||||
class tHyperlinkedModelSerializerOptions(serializers.HyperlinkedModelSerializerOptions):
|
||||
""" Options for PostHyperlinkedModelSerializer """
|
||||
|
||||
def __init__(self, meta):
|
||||
super(HyperlinkedModelSerializerOptions, self).__init__(meta)
|
||||
self.postonly_fields = getattr(meta, 'postonly_fields', ())
|
||||
|
||||
|
||||
class HyperlinkedModelSerializer(HyperlinkedModelSerializer):
|
||||
_options_class = HyperlinkedModelSerializerOptions
|
||||
|
||||
def to_native(self, obj):
|
||||
""" Serialize objects -> primitives. """
|
||||
ret = self._dict_class()
|
||||
ret.fields = {}
|
||||
|
||||
for field_name, field in self.fields.items():
|
||||
# Ignore all postonly_fields fron serialization
|
||||
if field_name in self.opts.postonly_fields:
|
||||
continue
|
||||
field.initialize(parent=self, field_name=field_name)
|
||||
key = self.get_field_key(field_name)
|
||||
value = field.field_to_native(obj, field_name)
|
||||
ret[key] = value
|
||||
ret.fields[key] = field
|
||||
return ret
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
model_attrs, post_attrs = {}, {}
|
||||
for attr, value in attrs.iteritems():
|
||||
if attr in self.opts.postonly_fields:
|
||||
post_attrs[attr] = value
|
||||
else:
|
||||
model_attrs[attr] = value
|
||||
obj = super(HyperlinkedModelSerializer, self).restore_object(model_attrs, instance)
|
||||
# Method to process ignored postonly_fields
|
||||
self.process_postonly_fields(obj, post_attrs)
|
||||
return obj
|
||||
|
||||
def process_postonly_fields(self, obj, post_attrs):
|
||||
""" Placeholder method for processing data sent in POST. """
|
||||
pass
|
||||
|
||||
|
||||
class MultiSelectField(serializers.ChoiceField):
|
||||
widget = widgets.CheckboxSelectMultiple
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.forms import widgets
|
|||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
from orchestra.core.validators import validate_password
|
||||
|
||||
|
@ -17,12 +18,14 @@ class RelatedDatabaseUserSerializer(serializers.HyperlinkedModelSerializer):
|
|||
return DatabaseUser.objects.get(username=data['username'])
|
||||
|
||||
|
||||
class DatabaseSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class DatabaseSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
users = RelatedDatabaseUserSerializer(many=True, allow_add_remove=True)
|
||||
# TODO clean user.type = db.type
|
||||
|
||||
class Meta:
|
||||
model = Database
|
||||
fields = ('url', 'name', 'type', 'users')
|
||||
postonly_fields = ('name', 'type')
|
||||
|
||||
|
||||
class RelatedDatabaseSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
@ -34,15 +37,17 @@ class RelatedDatabaseSerializer(serializers.HyperlinkedModelSerializer):
|
|||
return Database.objects.get(name=data['name'])
|
||||
|
||||
|
||||
class DatabaseUserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class DatabaseUserSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
password = serializers.CharField(max_length=128, label=_('Password'),
|
||||
validators=[validate_password], write_only=True,
|
||||
widget=widgets.PasswordInput)
|
||||
databases = RelatedDatabaseSerializer(many=True, allow_add_remove=True, required=False)
|
||||
|
||||
# TODO clean user.type = db.type
|
||||
|
||||
class Meta:
|
||||
model = DatabaseUser
|
||||
fields = ('url', 'username', 'password', 'type', 'databases')
|
||||
postonly_fields = ('username', 'type')
|
||||
|
||||
def save_object(self, obj, **kwargs):
|
||||
# FIXME this method will be called when saving nested serializers :(
|
||||
|
|
|
@ -165,6 +165,8 @@ class MySQLBackendMixin(object):
|
|||
"""mysql mysql -e 'SELECT * FROM db WHERE db="%(name)s";'""" % context, display=False).stdout)
|
||||
self.assertEqual('', sshrun(self.MASTER_SERVER,
|
||||
"""mysql mysql -e 'SELECT * FROM user WHERE user="%(username)s";'""" % context, display=False).stdout)
|
||||
|
||||
# TODO remove used from database
|
||||
|
||||
|
||||
class RESTDatabaseMixin(DatabaseTestMixin):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.core.exceptions import ValidationError
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
|
||||
from .helpers import domain_for_validation
|
||||
|
@ -17,13 +18,14 @@ class RecordSerializer(serializers.ModelSerializer):
|
|||
return data.get('value')
|
||||
|
||||
|
||||
class DomainSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
""" Validates if this zone generates a correct zone file """
|
||||
records = RecordSerializer(required=False, many=True, allow_add_remove=True)
|
||||
|
||||
class Meta:
|
||||
model = Domain
|
||||
fields = ('url', 'id', 'name', 'records')
|
||||
fields = ('url', 'name', 'records')
|
||||
postonly_fields = ('name',)
|
||||
|
||||
def full_clean(self, instance):
|
||||
""" Checks if everything is consistent """
|
||||
|
|
|
@ -2,15 +2,14 @@ from django.forms import widgets
|
|||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
from orchestra.core.validators import validate_password
|
||||
|
||||
from .models import List
|
||||
|
||||
|
||||
# TODO create PasswordSerializerMixin
|
||||
|
||||
class ListSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class ListSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
password = serializers.CharField(max_length=128, label=_('Password'),
|
||||
validators=[validate_password], write_only=True, required=False,
|
||||
widget=widgets.PasswordInput)
|
||||
|
@ -18,6 +17,7 @@ class ListSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeriali
|
|||
class Meta:
|
||||
model = List
|
||||
fields = ('url', 'name', 'address_name', 'address_domain', 'admin_email')
|
||||
postonly_fields = ('name',)
|
||||
|
||||
def validate_password(self, attrs, source):
|
||||
""" POST only password """
|
||||
|
|
|
@ -2,13 +2,14 @@ from django.forms import widgets
|
|||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
from orchestra.core.validators import validate_password
|
||||
|
||||
from .models import Mailbox, Address
|
||||
|
||||
|
||||
class MailboxSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class MailboxSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
password = serializers.CharField(max_length=128, label=_('Password'),
|
||||
validators=[validate_password], write_only=True, required=False,
|
||||
widget=widgets.PasswordInput)
|
||||
|
@ -18,6 +19,7 @@ class MailboxSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri
|
|||
fields = (
|
||||
'url', 'name', 'password', 'filtering', 'custom_filtering', 'addresses', 'is_active'
|
||||
)
|
||||
postonly_fields = ('name',)
|
||||
|
||||
def validate_password(self, attrs, source):
|
||||
""" POST only password """
|
||||
|
@ -54,4 +56,3 @@ class AddressSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri
|
|||
if not attrs['mailboxes'] and not attrs['forward']:
|
||||
raise serializers.ValidationError("mailboxes or forward addresses should be provided")
|
||||
return attrs
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.forms import widgets
|
|||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
from orchestra.core.validators import validate_password
|
||||
|
||||
|
@ -18,7 +19,7 @@ class GroupSerializer(serializers.ModelSerializer):
|
|||
return SystemUser.objects.get(username=data['username'])
|
||||
|
||||
|
||||
class SystemUserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class SystemUserSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
password = serializers.CharField(max_length=128, label=_('Password'),
|
||||
validators=[validate_password], write_only=True, required=False,
|
||||
widget=widgets.PasswordInput)
|
||||
|
@ -29,6 +30,7 @@ class SystemUserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelS
|
|||
fields = (
|
||||
'url', 'username', 'password', 'home', 'shell', 'groups', 'is_active',
|
||||
)
|
||||
postonly_fields = ('username',)
|
||||
|
||||
def validate_password(self, attrs, source):
|
||||
""" POST only password """
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.fields import OptionField
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
|
||||
from .models import WebApp
|
||||
|
||||
|
||||
class WebAppSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class WebAppSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
options = OptionField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = WebApp
|
||||
fields = ('url', 'name', 'type', 'options')
|
||||
postonly_fields = ('name', 'type')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from orchestra.api.fields import OptionField
|
||||
from orchestra.api.serializers import HyperlinkedModelSerializer
|
||||
from orchestra.apps.accounts.serializers import AccountSerializerMixin
|
||||
|
||||
from .models import Website, Content
|
||||
|
@ -15,7 +16,7 @@ class ContentSerializer(serializers.HyperlinkedModelSerializer):
|
|||
return '%s-%s' % (data.get('website'), data.get('path'))
|
||||
|
||||
|
||||
class WebsiteSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer):
|
||||
class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||
contents = ContentSerializer(required=False, many=True, allow_add_remove=True,
|
||||
source='content_set')
|
||||
options = OptionField(required=False)
|
||||
|
@ -23,3 +24,4 @@ class WebsiteSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeri
|
|||
class Meta:
|
||||
model = Website
|
||||
fields = ('url', 'name', 'port', 'domains', 'is_active', 'contents', 'options')
|
||||
postonly_fileds = ('name',)
|
||||
|
|
Loading…
Reference in a new issue