spaceport/apiserver/apiserver/api/serializers.py

378 lines
12 KiB
Python

from django.contrib.auth.models import User, Group
from django.shortcuts import get_object_or_404
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.validators import UniqueValidator
from rest_auth.registration.serializers import RegisterSerializer
from rest_auth.serializers import UserDetailsSerializer
import re
from . import models, fields, utils
from .. import settings
class TransactionSerializer(serializers.ModelSerializer):
# fields directly from old portal. replace with slugs we want
account_type = serializers.ChoiceField([
'Interac',
'TD Chequing',
'Dream Pmt',
'PayPal',
'Square Pmt',
'Member',
'Clearing',
'Cash'
])
info_source = serializers.ChoiceField([
'Web',
'DB Edit',
'System',
'Receipt or Stmt',
'Quicken Import',
'PayPal IPN',
'Auto',
'Nexus DB Bulk',
'IPN Trigger',
'Intranet Receipt',
'Automatic',
'Manual'
])
member_id = serializers.IntegerField()
member_name = serializers.SerializerMethodField()
date = serializers.DateField()
report_type = serializers.ChoiceField([
'Unmatched Member',
'Unmatched Purchase',
'User Flagged',
], allow_null=True, required=False)
class Meta:
model = models.Transaction
fields = '__all__'
read_only_fields = [
'id',
'last_seen_at',
'user',
'recorder',
'paypal_txn_id',
'paypal_payer_id',
]
def create(self, validated_data):
member = get_object_or_404(models.Member, id=validated_data['member_id'])
if member.user:
validated_data['user'] = member.user
return super().create(validated_data)
def update(self, instance, validated_data):
member = get_object_or_404(models.Member, id=validated_data['member_id'])
validated_data['user'] = member.user
return super().update(instance, validated_data)
def get_member_name(self, obj):
if not obj.member_id: return 'Unknown'
if obj.user:
member = obj.user.member
else:
member = models.Member.objects.get(id=obj.member_id)
return member.preferred_name + ' ' + member.last_name
# member viewing other members
class OtherMemberSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField()
class Meta:
model = models.Member
fields = [
'id',
'preferred_name',
'last_name',
'status',
'current_start_date',
'photo_small',
'photo_large'
]
def get_status(self, obj):
return 'Former Member' if obj.paused_date else obj.status
# member viewing his own details
class MemberSerializer(serializers.ModelSerializer):
status = serializers.SerializerMethodField()
photo = serializers.ImageField(write_only=True, required=False)
email = fields.UserEmailField(serializers.EmailField)
phone = serializers.CharField()
street_address = serializers.CharField()
city = serializers.CharField()
postal_code = serializers.CharField()
class Meta:
model = models.Member
fields = '__all__'
read_only_fields = [
'id',
'is_director',
'is_staff',
'is_instructor',
'first_name',
'last_name',
'status',
'expire_date',
'current_start_date',
'application_date',
'vetted_date',
'paused_date',
'monthly_fees',
'photo_large',
'photo_medium',
'photo_small',
'member_forms',
'user',
'old_email',
]
def get_status(self, obj):
return 'Former Member' if obj.paused_date else obj.status
def update(self, instance, validated_data):
if instance.user:
instance.user.email = validated_data.get('email', instance.user.email)
instance.user.save()
else:
instance.old_email = validated_data.get('email', instance.old_email)
photo = validated_data.get('photo', None)
if photo:
small, medium, large = utils.process_image_upload(photo)
instance.photo_small = small
instance.photo_medium = medium
instance.photo_large = large
return super().update(instance, validated_data)
# admin viewing member details
class AdminMemberSerializer(MemberSerializer):
class Meta:
model = models.Member
fields = '__all__'
read_only_fields = [
'id',
'status',
'expire_date',
'paused_date',
'photo_large',
'photo_medium',
'photo_small',
'member_forms',
'user',
'old_email',
]
# member viewing member list or search result
class SearchSerializer(serializers.Serializer):
q = serializers.CharField(write_only=True, max_length=64)
seq = serializers.IntegerField(write_only=True)
member = serializers.SerializerMethodField()
def get_member(self, obj):
serializer = OtherMemberSerializer(obj)
return serializer.data
# admin viewing search result
class AdminSearchSerializer(serializers.Serializer):
cards = serializers.SerializerMethodField()
member = serializers.SerializerMethodField()
transactions = serializers.SerializerMethodField()
def get_member(self, obj):
serializer = AdminMemberSerializer(obj)
return serializer.data
def get_cards(self, obj):
if obj.user:
queryset = obj.user.cards
else:
queryset = models.Card.objects.filter(member_id=obj.id)
queryset = queryset.order_by('-last_seen_at')
serializer = CardSerializer(data=queryset, many=True)
serializer.is_valid()
return serializer.data
def get_transactions(self, obj):
if obj.user:
queryset = obj.user.transactions
else:
queryset = models.Transaction.objects.filter(member_id=obj.id)
queryset = queryset.order_by('-id', '-date')
serializer = TransactionSerializer(data=queryset, many=True)
serializer.is_valid()
return serializer.data
class CardSerializer(serializers.ModelSerializer):
card_number = serializers.CharField(validators=[UniqueValidator(
queryset=models.Card.objects.all(),
message='Card number already exists.'
)])
member_id = serializers.IntegerField()
active_status = serializers.ChoiceField([
'card_blocked',
'card_inactive',
'card_member_blocked',
'card_active'
])
class Meta:
model = models.Card
fields = '__all__'
read_only_fields = [
'id',
'last_seen_at',
'user',
]
def create(self, validated_data):
member = get_object_or_404(models.Member, id=validated_data['member_id'])
if member.user:
validated_data['user'] = member.user
return super().create(validated_data)
class TrainingSerializer(serializers.ModelSerializer):
attendance_status = serializers.ChoiceField([
'Waiting for payment',
'Withdrawn',
'Rescheduled',
'No-show',
'Attended',
'Confirmed'
])
session = serializers.PrimaryKeyRelatedField(queryset=models.Session.objects.all())
student_name = serializers.SerializerMethodField()
class Meta:
model = models.Training
fields = '__all__'
read_only_fields = ['user', 'sign_up_date', 'paid_date', 'member_id']
def get_student_name(self, obj):
if obj.user:
member = obj.user.member
else:
member = models.Member.objects.get(id=obj.member_id)
return member.preferred_name + ' ' + member.last_name
class StudentTrainingSerializer(TrainingSerializer):
attendance_status = serializers.ChoiceField(['Waiting for payment', 'Withdrawn'])
class SessionSerializer(serializers.ModelSerializer):
student_count = serializers.SerializerMethodField()
course_name = serializers.SerializerMethodField()
instructor_name = serializers.SerializerMethodField()
datetime = serializers.DateTimeField()
course = serializers.PrimaryKeyRelatedField(queryset=models.Course.objects.all())
students = TrainingSerializer(many=True, read_only=True)
class Meta:
model = models.Session
fields = '__all__'
read_only_fields = ['old_instructor', 'instructor']
def get_student_count(self, obj):
return len([x for x in obj.students.all() if x.attendance_status != 'Withdrawn'])
def get_course_name(self, obj):
return obj.course.name
def get_instructor_name(self, obj):
if obj.instructor and hasattr(obj.instructor, 'member'):
name = '{} {}'.format(obj.instructor.member.preferred_name, obj.instructor.member.last_name[0])
else:
name = 'Unknown'
return obj.old_instructor or name
class SessionListSerializer(SessionSerializer):
students = None
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = models.Course
fields = ['id', 'name']
class CourseDetailSerializer(serializers.ModelSerializer):
sessions = SessionListSerializer(many=True, read_only=True)
name = serializers.CharField(max_length=100)
description = fields.HTMLField(max_length=6000)
class Meta:
model = models.Course
fields = '__all__'
class UserTrainingSerializer(serializers.ModelSerializer):
session = SessionListSerializer()
class Meta:
model = models.Training
exclude = ['user']
depth = 2
class UserSerializer(serializers.ModelSerializer):
training = UserTrainingSerializer(many=True)
member = MemberSerializer()
transactions = serializers.SerializerMethodField()
class Meta:
model = User
fields = [
'id',
'username',
'member',
'transactions',
'cards',
'training',
'is_staff'
]
depth = 1
def get_transactions(self, obj):
queryset = models.Transaction.objects.filter(user=obj)
queryset = queryset.exclude(category='Memberships:Fake Months')
queryset = queryset.order_by('-id', '-date')
serializer = TransactionSerializer(data=queryset, many=True)
serializer.is_valid()
return serializer.data
class RegistrationSerializer(RegisterSerializer):
first_name = serializers.CharField(max_length=32)
last_name = serializers.CharField(max_length=32)
existing_member = serializers.ChoiceField(['true', 'false'])
def validate_username(self, username):
if re.search(r'[^a-z.]', username):
raise ValidationError('Invalid characters.')
return super().validate_username(username)
def custom_signup(self, request, user):
data = request.data
is_test_signup = bool(data['last_name'] == 'tester')
if not utils.is_request_from_protospace(request) and not is_test_signup:
user.delete()
raise ValidationError(dict(non_field_errors='Can only register from Protospace.'))
if data['existing_member'] == 'true':
utils.link_old_member(data, user)
else:
models.Member.objects.create(
user=user,
first_name=data['first_name'],
last_name=data['last_name'],
preferred_name=data['first_name'],
)