# pylint: disable=abstract-method
import collections
import functools
import logging
from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Count
from rest_framework import serializers
from rest_framework.reverse import reverse
from .models import EighthActivity, EighthBlock, EighthScheduledActivity, EighthSignup, EighthSponsor
logger = logging.getLogger(__name__)
[docs]class EighthActivityListSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="api_eighth_activity_detail")
[docs]class EighthActivityDetailSerializer(serializers.HyperlinkedModelSerializer):
scheduled_on = serializers.SerializerMethodField("fetch_scheduled_on")
[docs] def fetch_scheduled_on(self, act):
scheduled_on = collections.OrderedDict()
scheduled_activities = EighthScheduledActivity.objects.filter(activity=act).select_related("block").order_by("block__date")
# user = self.context.get("user", self.context["request"].user)
# favorited_activities = set(user.favorited_activity_set
# .values_list("id", flat=True))
# available_restricted_acts = EighthActivity.restricted_activities_available_to_user(user)
for scheduled_activity in scheduled_activities:
scheduled_on[scheduled_activity.block.id] = {
"id": scheduled_activity.block.id,
"date": scheduled_activity.block.date,
"block_letter": scheduled_activity.block.block_letter,
"url": reverse("api_eighth_block_detail", args=[scheduled_activity.block.id], request=self.context["request"]),
"roster": {
"id": scheduled_activity.id,
"url": reverse("api_eighth_scheduled_activity_signup_list", args=[scheduled_activity.id], request=self.context["request"]),
},
}
return scheduled_on
[docs]class EighthBlockListSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="api_eighth_block_detail")
[docs]class FallbackDict(dict):
def __init__(self, fallback):
super().__init__()
self.fallback = fallback
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
return self.fallback(key)
[docs]class EighthBlockDetailSerializer(serializers.Serializer):
id = serializers.ReadOnlyField()
activities = serializers.SerializerMethodField("fetch_activity_list_with_metadata")
date = serializers.DateField()
block_letter = serializers.CharField(max_length=10)
comments = serializers.CharField(max_length=100)
[docs] def process_scheduled_activity(
self,
scheduled_activity,
request=None,
user=None,
favorited_activities=None,
subscribed_activities=None,
recommended_activities=None,
available_restricted_acts=None,
):
activity = scheduled_activity.activity
if user:
is_non_student_admin = user.is_eighth_admin and not user.is_student
else:
is_non_student_admin = False
restricted_for_user = scheduled_activity.get_restricted() and not is_non_student_admin and (activity.id not in available_restricted_acts)
prefix = "Special: " if activity.special else ""
prefix += activity.name
if scheduled_activity.title:
prefix += " - " + scheduled_activity.title
middle = " (R)" if restricted_for_user else ""
if user is not None and scheduled_activity.is_user_stickied(user):
suffix = " (S)"
else:
suffix = ""
suffix += " (BB)" if scheduled_activity.is_both_blocks() else ""
suffix += " (A)" if activity.administrative else ""
suffix += " (Deleted)" if activity.deleted else ""
name_with_flags = prefix + middle + suffix
name_with_flags_for_user = prefix + (middle if restricted_for_user else "") + suffix
activity_info = {
"id": activity.id,
"aid": activity.aid,
"scheduled_activity": {
"id": scheduled_activity.id,
"url": reverse("api_eighth_scheduled_activity_signup_list", args=[scheduled_activity.id], request=request),
},
"url": reverse("api_eighth_activity_detail", args=[activity.id], request=request),
"name": activity.name,
"name_with_flags": name_with_flags,
"name_with_flags_for_user": name_with_flags_for_user,
"description": activity.description,
"cancelled": scheduled_activity.cancelled,
"favorited": activity.id in favorited_activities,
"subscribed_to": activity.id in subscribed_activities,
"subscriptions_enabled": activity.subscriptions_enabled,
"roster": {
"count": 0,
"capacity": 0,
"url": reverse("api_eighth_scheduled_activity_signup_list", args=[scheduled_activity.id], request=request),
},
"rooms": [],
"sponsors": [],
"restricted": scheduled_activity.get_restricted(),
"restricted_for_user": restricted_for_user,
"both_blocks": scheduled_activity.is_both_blocks(),
"one_a_day": activity.one_a_day,
"special": scheduled_activity.get_special(),
"administrative": scheduled_activity.get_administrative(),
"presign": activity.presign,
"presign_time": scheduled_activity.is_too_early_to_signup()[1].strftime("%A, %B %-d at %-I:%M %p"),
"sticky": scheduled_activity.is_activity_sticky(),
"user_sticky": scheduled_activity.is_user_stickied(user),
"finance": "", # TODO: refactor JS to remove this
"title": scheduled_activity.title,
"comments": scheduled_activity.comments, # TODO: refactor JS to remove this
"display_text": "",
# TODO: Remove together with other eighth waitlist functionality
"waitlist_count": 0,
}
if user:
# TODO: Remove together with other eighth waitlist functionality
activity_info["waitlisted"] = False
activity_info["waitlist_position"] = 0
activity_info["is_recommended"] = activity in recommended_activities
return activity_info
[docs] def get_activity(
self,
user,
favorited_activities,
subscribed_activities,
recommended_activities,
available_restricted_acts,
block_id,
activity_id,
scheduled_activity=None,
):
if scheduled_activity is None:
scheduled_activity = EighthScheduledActivity.objects.get(block_id=block_id, activity_id=activity_id)
return self.process_scheduled_activity(
scheduled_activity,
self.context["request"],
user,
favorited_activities,
subscribed_activities,
recommended_activities,
available_restricted_acts,
)
[docs] def get_scheduled_activity(self, scheduled_activity_id):
return EighthScheduledActivity.objects.get(id=scheduled_activity_id).activity_id
[docs]class EighthSignupSerializer(serializers.ModelSerializer):
block = serializers.SerializerMethodField("block_info")
activity = serializers.SerializerMethodField("activity_info")
scheduled_activity = serializers.SerializerMethodField("scheduled_activity_info")
[docs] def block_info(self, signup):
return {
"id": signup.scheduled_activity.block.id,
"date": signup.scheduled_activity.block.date,
"url": reverse("api_eighth_block_detail", args=[signup.scheduled_activity.block.id], request=self.context["request"]),
"block_letter": signup.scheduled_activity.block.block_letter,
}
[docs] def activity_info(self, signup):
return {
"id": signup.scheduled_activity.activity.id,
"title": signup.scheduled_activity.title_with_flags,
"url": reverse("api_eighth_activity_detail", args=[signup.scheduled_activity.activity.id], request=self.context["request"]),
}
[docs] def scheduled_activity_info(self, signup):
return signup.scheduled_activity.id
[docs]class UserSerializer(serializers.ModelSerializer):
url = serializers.SerializerMethodField()
[docs] def get_url(self, user):
return reverse("api_user_profile_detail", args=[user.id], request=self.context["request"])
[docs]class EighthScheduledActivitySerializer(serializers.ModelSerializer):
block = serializers.SerializerMethodField("block_info")
activity = serializers.SerializerMethodField("activity_info")
signups = serializers.SerializerMethodField("signups_info")
name = serializers.SerializerMethodField()
capacity = serializers.SerializerMethodField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if "context" in kwargs and "request" in kwargs["context"]:
self.request = kwargs["context"]["request"]
else:
self.request = None
[docs] def get_name(self, scheduled_activity):
return scheduled_activity.title_with_flags
[docs] def get_capacity(self, scheduled_activity):
return scheduled_activity.get_true_capacity()
[docs] def block_info(self, scheduled_activity):
return {
"id": scheduled_activity.block.id,
"date": scheduled_activity.block.date,
"url": reverse("api_eighth_block_detail", args=[scheduled_activity.block.id], request=self.context["request"]),
}
[docs] def activity_info(self, scheduled_activity):
return {
"id": scheduled_activity.activity.id,
"title": scheduled_activity.title_with_flags,
"url": reverse("api_eighth_activity_detail", args=[scheduled_activity.activity.id], request=self.context["request"]),
}
[docs] def signups_info(self, scheduled_activity):
signups = scheduled_activity.members
if self.request:
signups = scheduled_activity.get_viewable_members_serializer(self.request)
serializer = UserSerializer(signups, context=self.context, many=True)
return {"members": serializer.data, "count": scheduled_activity.members.count(), "viewable_count": signups.count()}
[docs] def num_signups(self, scheduled_activity):
return scheduled_activity.members.count()
[docs]def add_signup_validator(value):
if "scheduled_activity" in value:
return
if "block" in value and "activity" in value and not value.get("use_scheduled_activity", False):
return
raise serializers.ValidationError(
"Either scheduled_activity, or block and activity must exist. use_scheduled_activity must be false to use block and activity."
)
[docs]class EighthAddSignupSerializer(serializers.Serializer):
block = serializers.PrimaryKeyRelatedField(queryset=EighthBlock.objects.all(), required=False)
activity = serializers.PrimaryKeyRelatedField(queryset=EighthActivity.objects.all(), required=False)
scheduled_activity = serializers.PrimaryKeyRelatedField(
queryset=EighthScheduledActivity.objects.select_related("activity").select_related("block"), required=False
)
use_scheduled_activity = serializers.BooleanField(required=False)
force = serializers.BooleanField(required=False)
[docs]class EighthToggleFavoriteSerializer(serializers.Serializer):
activity = serializers.PrimaryKeyRelatedField(queryset=EighthActivity.objects.all(), required=False)