Skip to content

Commit c552a6c

Browse files
committed
Merge pull request #122 from helgi/serialized
ref(api): Remove a DRF hack around UUID and UniqueTogether
2 parents 75b420f + eff823e commit c552a6c

2 files changed

Lines changed: 34 additions & 29 deletions

File tree

rootfs/api/serializers.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from django.contrib.auth.models import User
1212
from django.utils import timezone
1313
from rest_framework import serializers
14-
from rest_framework.validators import UniqueTogetherValidator
1514

1615
from api import models
1716

@@ -77,23 +76,6 @@ def to_internal_value(self, data):
7776
return field
7877

7978

80-
class ModelSerializer(serializers.ModelSerializer):
81-
82-
uuid = serializers.ReadOnlyField()
83-
84-
def get_validators(self):
85-
"""
86-
Hack to remove DRF's UniqueTogetherValidator when it concerns the UUID.
87-
88-
See https://github.com/deis/deis/pull/2898#discussion_r23105147
89-
"""
90-
validators = super(ModelSerializer, self).get_validators()
91-
for v in validators:
92-
if isinstance(v, UniqueTogetherValidator) and 'uuid' in v.fields:
93-
validators.remove(v)
94-
return validators
95-
96-
9779
class UserSerializer(serializers.ModelSerializer):
9880
class Meta:
9981
model = User
@@ -113,14 +95,18 @@ def create(self, validated_data):
11395
date_joined=now,
11496
is_active=True
11597
)
98+
11699
if validated_data.get('first_name'):
117100
user.first_name = validated_data['first_name']
101+
118102
if validated_data.get('last_name'):
119103
user.last_name = validated_data['last_name']
104+
120105
user.set_password(validated_data['password'])
121106
# Make the first signup an admin / superuser
122107
if not User.objects.filter(is_superuser=True).exists():
123108
user.is_superuser = user.is_staff = True
109+
124110
user.save()
125111
return user
126112

@@ -134,7 +120,7 @@ class Meta:
134120
read_only_fields = ['username']
135121

136122

137-
class AppSerializer(ModelSerializer):
123+
class AppSerializer(serializers.ModelSerializer):
138124
"""Serialize a :class:`~api.models.App` model."""
139125

140126
owner = serializers.ReadOnlyField(source='owner.username')
@@ -149,7 +135,7 @@ class Meta:
149135
read_only_fields = ['uuid']
150136

151137

152-
class BuildSerializer(ModelSerializer):
138+
class BuildSerializer(serializers.ModelSerializer):
153139
"""Serialize a :class:`~api.models.Build` model."""
154140

155141
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())
@@ -166,7 +152,7 @@ class Meta:
166152
read_only_fields = ['uuid']
167153

168154

169-
class ConfigSerializer(ModelSerializer):
155+
class ConfigSerializer(serializers.ModelSerializer):
170156
"""Serialize a :class:`~api.models.Config` model."""
171157

172158
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())
@@ -188,49 +174,61 @@ def validate_values(self, value):
188174
raise serializers.ValidationError(
189175
"Config keys must start with a letter or underscore and "
190176
"only contain [A-z0-9_]")
177+
191178
return value
192179

193180
def validate_memory(self, value):
194181
for k, v in value.viewitems():
195182
if v is None: # use NoneType to unset a value
196183
continue
184+
197185
if not re.match(PROCTYPE_MATCH, k):
198186
raise serializers.ValidationError("Process types can only contain [a-z]")
187+
199188
if not re.match(MEMLIMIT_MATCH, str(v)):
200189
raise serializers.ValidationError(
201190
"Limit format: <number><unit>, where unit = B, K, M or G")
191+
202192
return value
203193

204194
def validate_cpu(self, value):
205195
for k, v in value.viewitems():
206196
if v is None: # use NoneType to unset a value
207197
continue
198+
208199
if not re.match(PROCTYPE_MATCH, k):
209200
raise serializers.ValidationError("Process types can only contain [a-z]")
201+
210202
shares = re.match(CPUSHARE_MATCH, str(v))
211203
if not shares:
212204
raise serializers.ValidationError("CPU shares must be an integer")
205+
213206
for v in shares.groupdict().viewvalues():
214207
try:
215208
i = int(v)
216209
except ValueError:
217210
raise serializers.ValidationError("CPU shares must be an integer")
211+
218212
if i > 1024 or i < 0:
219213
raise serializers.ValidationError("CPU shares must be between 0 and 1024")
214+
220215
return value
221216

222217
def validate_tags(self, value):
223218
for k, v in value.viewitems():
224219
if v is None: # use NoneType to unset a value
225220
continue
221+
226222
if not re.match(TAGKEY_MATCH, k):
227223
raise serializers.ValidationError("Tag keys can only contain [a-z]")
224+
228225
if not re.match(TAGVAL_MATCH, str(v)):
229226
raise serializers.ValidationError("Invalid tag value")
227+
230228
return value
231229

232230

233-
class ReleaseSerializer(ModelSerializer):
231+
class ReleaseSerializer(serializers.ModelSerializer):
234232
"""Serialize a :class:`~api.models.Release` model."""
235233

236234
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())
@@ -243,7 +241,7 @@ class Meta:
243241
model = models.Release
244242

245243

246-
class ContainerSerializer(ModelSerializer):
244+
class ContainerSerializer(serializers.ModelSerializer):
247245
"""Serialize a :class:`~api.models.Container` model."""
248246

249247
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())
@@ -261,7 +259,7 @@ def get_release(self, obj):
261259
return "v{}".format(obj.release.version)
262260

263261

264-
class KeySerializer(ModelSerializer):
262+
class KeySerializer(serializers.ModelSerializer):
265263
"""Serialize a :class:`~api.models.Key` model."""
266264

267265
owner = serializers.ReadOnlyField(source='owner.username')
@@ -274,7 +272,7 @@ class Meta:
274272
model = models.Key
275273

276274

277-
class DomainSerializer(ModelSerializer):
275+
class DomainSerializer(serializers.ModelSerializer):
278276
"""Serialize a :class:`~api.models.Domain` model."""
279277

280278
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())
@@ -285,35 +283,41 @@ class DomainSerializer(ModelSerializer):
285283
class Meta:
286284
"""Metadata options for a :class:`DomainSerializer`."""
287285
model = models.Domain
288-
fields = ['uuid', 'owner', 'created', 'updated', 'app', 'domain']
286+
fields = ['owner', 'created', 'updated', 'app', 'domain']
289287

290288
def validate_domain(self, value):
291289
"""
292290
Check that the hostname is valid
293291
"""
294292
if len(value) > 255:
295293
raise serializers.ValidationError('Hostname must be 255 characters or less.')
294+
296295
if value[-1:] == ".":
297296
value = value[:-1] # strip exactly one dot from the right, if present
297+
298298
labels = value.split('.')
299299
if 'xip.io' in value:
300300
return value
301+
301302
if labels[0] == '*':
302303
raise serializers.ValidationError(
303304
'Adding a wildcard subdomain is currently not supported.')
305+
304306
allowed = re.compile("^(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
305307
for label in labels:
306308
match = allowed.match(label)
307309
if not match or '--' in label or label.isdigit() or \
308310
len(labels) == 1 and any(char.isdigit() for char in label):
309311
raise serializers.ValidationError('Hostname does not look valid.')
312+
310313
if models.Domain.objects.filter(domain=value).exists():
311314
raise serializers.ValidationError(
312315
"The domain {} is already in use by another app".format(value))
316+
313317
return value
314318

315319

316-
class CertificateSerializer(ModelSerializer):
320+
class CertificateSerializer(serializers.ModelSerializer):
317321
"""Serialize a :class:`~api.models.Cert` model."""
318322

319323
owner = serializers.ReadOnlyField(source='owner.username')
@@ -330,7 +334,7 @@ class Meta:
330334
read_only_fields = ['expires', 'created', 'updated']
331335

332336

333-
class PushSerializer(ModelSerializer):
337+
class PushSerializer(serializers.ModelSerializer):
334338
"""Serialize a :class:`~api.models.Push` model."""
335339

336340
app = serializers.SlugRelatedField(slug_field='id', queryset=models.App.objects.all())

rootfs/api/tests/test_release.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from __future__ import unicode_literals
88

99
import json
10+
import uuid
1011

1112
from django.contrib.auth.models import User
1213
from django.test import TransactionTestCase
@@ -124,7 +125,7 @@ def test_response_data(self):
124125
'owner': self.user.username,
125126
'app': 'test',
126127
'build': None,
127-
'config': config_response.data['uuid'],
128+
'config': uuid.UUID(config_response.data['uuid']),
128129
'summary': '{} added NEW_URL'.format(self.user.username),
129130
'version': 2
130131
}

0 commit comments

Comments
 (0)