From ec447e0dc4a28e29de11f269c1e42bf39d7ed11a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 10 May 2020 21:47:44 +0200 Subject: [PATCH] Add support for primary address in user. Closes #35 Fixes #35 --- uncloud/urls.py | 1 - .../0004_user_primary_billing_address.py | 20 +++++++++++++++ .../migrations/0005_auto_20200510_1736.py | 20 +++++++++++++++ uncloud_auth/models.py | 7 +++++- uncloud_auth/serializers.py | 19 ++++++++++---- uncloud_auth/views.py | 25 ++++++++++++++----- .../migrations/0014_paymentsettings.py | 25 +++++++++++++++++++ uncloud_pay/serializers.py | 2 ++ 8 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 uncloud_auth/migrations/0004_user_primary_billing_address.py create mode 100644 uncloud_auth/migrations/0005_auto_20200510_1736.py create mode 100644 uncloud_pay/migrations/0014_paymentsettings.py diff --git a/uncloud/urls.py b/uncloud/urls.py index b20f136..723ef45 100644 --- a/uncloud/urls.py +++ b/uncloud/urls.py @@ -63,7 +63,6 @@ router.register(r'v1/my/order', payviews.OrderViewSet, basename='order') router.register(r'v1/my/payment', payviews.PaymentViewSet, basename='payment') router.register(r'v1/my/payment-method', payviews.PaymentMethodViewSet, basename='payment-method') - # admin/staff urls router.register(r'v1/admin/bill', payviews.AdminBillViewSet, basename='admin/bill') router.register(r'v1/admin/payment', payviews.AdminPaymentViewSet, basename='admin/payment') diff --git a/uncloud_auth/migrations/0004_user_primary_billing_address.py b/uncloud_auth/migrations/0004_user_primary_billing_address.py new file mode 100644 index 0000000..640c9c5 --- /dev/null +++ b/uncloud_auth/migrations/0004_user_primary_billing_address.py @@ -0,0 +1,20 @@ +# Generated by Django 3.0.6 on 2020-05-10 17:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0014_paymentsettings'), + ('uncloud_auth', '0003_auto_20200318_1345'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='primary_billing_address', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='uncloud_pay.BillingAddress'), + ), + ] diff --git a/uncloud_auth/migrations/0005_auto_20200510_1736.py b/uncloud_auth/migrations/0005_auto_20200510_1736.py new file mode 100644 index 0000000..38c303e --- /dev/null +++ b/uncloud_auth/migrations/0005_auto_20200510_1736.py @@ -0,0 +1,20 @@ +# Generated by Django 3.0.6 on 2020-05-10 17:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0014_paymentsettings'), + ('uncloud_auth', '0004_user_primary_billing_address'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='primary_billing_address', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='uncloud_pay.BillingAddress'), + ), + ] diff --git a/uncloud_auth/models.py b/uncloud_auth/models.py index 4549a2a..c456648 100644 --- a/uncloud_auth/models.py +++ b/uncloud_auth/models.py @@ -3,7 +3,6 @@ from django.db import models from django.core.validators import MinValueValidator from uncloud_pay import AMOUNT_DECIMALS, AMOUNT_MAX_DIGITS - from uncloud_pay.models import get_balance_for_user class User(AbstractUser): @@ -18,6 +17,12 @@ class User(AbstractUser): decimal_places=AMOUNT_DECIMALS, validators=[MinValueValidator(0)]) + # Need to use the string here to prevent a circular import + primary_billing_address = models.ForeignKey('uncloud_pay.BillingAddress', + on_delete=models.PROTECT, + blank=True, + null=True) + @property def balance(self): return get_balance_for_user(self) diff --git a/uncloud_auth/serializers.py b/uncloud_auth/serializers.py index e01aab3..92bbf01 100644 --- a/uncloud_auth/serializers.py +++ b/uncloud_auth/serializers.py @@ -2,15 +2,24 @@ from django.contrib.auth import get_user_model from rest_framework import serializers from uncloud_pay import AMOUNT_DECIMALS, AMOUNT_MAX_DIGITS +from uncloud_pay.models import BillingAddress class UserSerializer(serializers.ModelSerializer): - - balance = serializers.DecimalField(max_digits=AMOUNT_MAX_DIGITS, - decimal_places=AMOUNT_DECIMALS) - class Meta: model = get_user_model() - fields = ['username', 'email', 'balance', 'maximum_credit' ] + read_only_fields = [ 'username', 'balance', 'maximum_credit' ] + fields = read_only_fields + [ 'email', 'primary_billing_address' ] + + def validate(self, data): + """ + Ensure that the primary billing address belongs to the user + """ + + if 'primary_billing_address' in data: + if not data['primary_billing_address'].owner == self.instance: + raise serializers.ValidationError("Invalid data") + + return data class ImportUserSerializer(serializers.Serializer): username = serializers.CharField() diff --git a/uncloud_auth/views.py b/uncloud_auth/views.py index 9c5bd1f..77f0a0f 100644 --- a/uncloud_auth/views.py +++ b/uncloud_auth/views.py @@ -3,24 +3,37 @@ from .serializers import * from django_auth_ldap.backend import LDAPBackend from rest_framework.decorators import action from rest_framework.response import Response -from rest_framework import mixins -class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): +class UserViewSet(viewsets.GenericViewSet): permission_classes = [permissions.IsAuthenticated] serializer_class = UserSerializer + def get_queryset(self): + return self.request.user + def list(self, request, format=None): # This is a bit stupid: we have a user, we create a queryset by # matching on the username. But I don't know a "nicer" way. # Nico, 2020-03-18 - user = get_user_model().objects.get( - username=self.request.user.username) + user = request.user serializer = self.get_serializer(user, context = {'request': request}) return Response(serializer.data) + def create(self, request): + """ + Modify existing user data + """ + + user = request.user + serializer = self.get_serializer(user, + context = {'request': request}, + data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response(serializer.data) + class AdminUserViewSet(viewsets.ReadOnlyModelViewSet): - # FIXME: make this admin - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] def get_serializer_class(self): if self.action == 'import_from_ldap': diff --git a/uncloud_pay/migrations/0014_paymentsettings.py b/uncloud_pay/migrations/0014_paymentsettings.py new file mode 100644 index 0000000..2a4f9a0 --- /dev/null +++ b/uncloud_pay/migrations/0014_paymentsettings.py @@ -0,0 +1,25 @@ +# Generated by Django 3.0.6 on 2020-05-10 13:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('uncloud_pay', '0013_auto_20200508_1446'), + ] + + operations = [ + migrations.CreateModel( + name='PaymentSettings', + fields=[ + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('owner', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('primary_billing_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.BillingAddress')), + ], + ), + ] diff --git a/uncloud_pay/serializers.py b/uncloud_pay/serializers.py index edccd07..5ee5ad5 100644 --- a/uncloud_pay/serializers.py +++ b/uncloud_pay/serializers.py @@ -1,6 +1,8 @@ from django.contrib.auth import get_user_model from rest_framework import serializers from uncloud_auth.serializers import UserSerializer +from django.utils.translation import gettext_lazy as _ + from .models import * ###