diff --git a/program/models.py b/program/models.py index 6a58ae8dfd78afb6e82dbe409a37b0463ebf9132..06b4a775377cd16728627525303cc3e551a72260 100644 --- a/program/models.py +++ b/program/models.py @@ -35,9 +35,9 @@ class ScheduleConflictError(ValidationError): class Type(models.Model): - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) - slug = models.SlugField(max_length=32, unique=True) + is_active = models.BooleanField(default=True, help_text="True if type is active.") + name = models.CharField(max_length=32, help_text="Name of the type.") + slug = models.SlugField(max_length=32, unique=True, help_text="Slug of the type.") class Meta: ordering = ("name",) @@ -47,11 +47,11 @@ class Type(models.Model): class Category(models.Model): - description = models.TextField(blank=True) - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) - slug = models.SlugField(max_length=32, unique=True) - subtitle = models.CharField(blank=True, max_length=32) + description = models.TextField(blank=True, help_text="Description of the category.") + is_active = models.BooleanField(default=True, help_text="True if category is active.") + name = models.CharField(max_length=32, help_text="Name of the category.") + slug = models.SlugField(max_length=32, unique=True, help_text="Slug of the category.") + subtitle = models.CharField(blank=True, max_length=32, help_text="Subtitle of the category.") class Meta: ordering = ("name",) @@ -62,9 +62,9 @@ class Category(models.Model): class Topic(models.Model): - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) - slug = models.SlugField(max_length=32, unique=True) + is_active = models.BooleanField(default=True, help_text="True if topic is active.") + name = models.CharField(max_length=32, help_text="Name of the topic.") + slug = models.SlugField(max_length=32, unique=True, help_text="Slug of the topic.") class Meta: ordering = ("name",) @@ -74,9 +74,9 @@ class Topic(models.Model): class MusicFocus(models.Model): - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) - slug = models.SlugField(max_length=32, unique=True) + is_active = models.BooleanField(default=True, help_text="True if music focus is active.") + name = models.CharField(max_length=32, help_text="Name of the music focus.") + slug = models.SlugField(max_length=32, unique=True, help_text="Slug of the music focus.") class Meta: ordering = ("name",) @@ -87,9 +87,9 @@ class MusicFocus(models.Model): class FundingCategory(models.Model): - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) - slug = models.SlugField(max_length=32, unique=True) + is_active = models.BooleanField(default=True, help_text="True if funding category is active.") + name = models.CharField(max_length=32, help_text="Name of the funding category.") + slug = models.SlugField(max_length=32, unique=True, help_text="Slug of the funding category.") class Meta: ordering = ("name",) @@ -100,8 +100,8 @@ class FundingCategory(models.Model): class Language(models.Model): - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=32) + is_active = models.BooleanField(default=True, help_text="True if language is active.") + name = models.CharField(max_length=32, help_text="Name of the language.") class Meta: ordering = ("name",) @@ -113,9 +113,11 @@ class Language(models.Model): class License(models.Model): identifier = models.CharField(max_length=32, help_text="Identifier of the license") name = models.CharField(max_length=64, help_text="Name of the license") - needs_author = models.BooleanField(default=True) - requires_express_permission_for_publication = models.BooleanField(default=True) - url = models.URLField(default="", blank=True) + needs_author = models.BooleanField(default=True, help_text="True if license needs an author.") + requires_express_permission_for_publication = models.BooleanField( + default=True, help_text="True if express permission for publication required." + ) + url = models.URLField(default="", blank=True, help_text="URL of the licence.") class Meta: ordering = ("name",) @@ -125,9 +127,11 @@ class License(models.Model): class Image(models.Model): - alt_text = models.TextField(blank=True, default="") - credits = models.TextField(blank=True, default="") - is_use_explicitly_granted_by_author = models.BooleanField(default=False) + alt_text = models.TextField(blank=True, default="", help_text="Alternate text for the image.") + credits = models.TextField(blank=True, default="", help_text="Credits of the image") + is_use_explicitly_granted_by_author = models.BooleanField( + default=False, help_text="True if use is explicitly granted by author." + ) height = models.PositiveIntegerField(blank=True, null=True) image = VersatileImageField( blank=True, @@ -136,6 +140,7 @@ class Image(models.Model): ppoi_field="ppoi", upload_to="images", width_field="width", + help_text="The URI of the image.", ) license = models.ForeignKey( License, null=True, on_delete=models.SET_NULL, related_name="images" @@ -158,14 +163,16 @@ class Image(models.Model): class Host(models.Model): - biography = models.TextField(blank=True) + biography = models.TextField(blank=True, help_text="Biography of the host.") created_at = models.DateTimeField(auto_now_add=True) created_by = models.CharField(max_length=150) - email = models.EmailField(blank=True) + email = models.EmailField(blank=True, help_text="Email address of the host.") image = models.ForeignKey(Image, null=True, on_delete=models.CASCADE, related_name="hosts") - is_active = models.BooleanField(default=True) - name = models.CharField(max_length=128) - owners = models.ManyToManyField(User, blank=True, related_name="hosts") + is_active = models.BooleanField(default=True, help_text="True if host is active.") + name = models.CharField(max_length=128, help_text="Display name of the host.") + owners = models.ManyToManyField( + User, blank=True, related_name="hosts", help_text="User ID(s) identifying this host." + ) updated_at = models.DateTimeField(auto_now=True, blank=True, null=True) updated_by = models.CharField(blank=True, default="", max_length=150) @@ -183,7 +190,7 @@ class Host(models.Model): class LinkType(models.Model): - is_active = models.BooleanField(default=True) + is_active = models.BooleanField(default=True, help_text="True if link type is active.") name = models.CharField(max_length=32, help_text="Name of the link type") class Meta: @@ -221,29 +228,31 @@ class Show(models.Model): created_at = models.DateTimeField(auto_now_add=True) created_by = models.CharField(max_length=150) default_playlist_id = models.IntegerField(blank=True, null=True) - description = models.TextField(blank=True) - email = models.EmailField(blank=True, null=True) + description = models.TextField(blank=True, help_text="Description of this show.") + email = models.EmailField(blank=True, null=True, help_text="Email address of this show.") funding_category = models.ForeignKey( FundingCategory, blank=True, null=True, on_delete=models.CASCADE, related_name="shows" ) hosts = models.ManyToManyField(Host, blank=True, related_name="shows") image = models.ForeignKey(Image, null=True, on_delete=models.CASCADE, related_name="shows") - internal_note = models.TextField(blank=True) - is_active = models.BooleanField(default=True) - is_public = models.BooleanField(default=False) + internal_note = models.TextField(blank=True, help_text="Internal note for this show.") + is_active = models.BooleanField(default=True, help_text="True if this show is active.") + is_public = models.BooleanField(default=False, help_text="True if this show is public.") language = models.ManyToManyField(Language, blank=True, related_name="shows") # TODO: is this really necessary? logo = models.ForeignKey( Image, blank=True, null=True, on_delete=models.CASCADE, related_name="logo_shows" ) music_focus = models.ManyToManyField(MusicFocus, blank=True, related_name="shows") - name = models.CharField(max_length=255) + name = models.CharField(max_length=255, help_text="Name of this Show.") owners = models.ManyToManyField(User, blank=True, related_name="shows") predecessor = models.ForeignKey( "self", blank=True, null=True, on_delete=models.CASCADE, related_name="successors" ) - short_description = models.TextField() - slug = models.SlugField(blank=True, max_length=255, unique=True) + short_description = models.TextField(help_text="Short description of this show.") + slug = models.SlugField( + blank=True, max_length=255, unique=True, help_text="Slug of this show." + ) topic = models.ManyToManyField(Topic, blank=True, related_name="shows") type = models.ForeignKey( Type, blank=True, null=True, on_delete=models.CASCADE, related_name="shows" @@ -422,8 +431,8 @@ class Schedule(models.Model): class TimeSlot(models.Model): end = models.DateTimeField() - memo = models.TextField(blank=True) - playlist_id = models.IntegerField(null=True) + memo = models.TextField(blank=True, help_text="Memo for this timeslot.") + playlist_id = models.IntegerField(null=True, help_text="`Playlist` ID of this timeslot.") repetition_of = models.ForeignKey( "self", blank=True, null=True, on_delete=models.CASCADE, related_name="repetitions" ) @@ -461,18 +470,22 @@ class TimeSlot(models.Model): class Note(models.Model): - cba_id = models.IntegerField(blank=True, null=True) - content = models.TextField() - contributors = models.ManyToManyField(Host, related_name="notes") + cba_id = models.IntegerField(blank=True, null=True, help_text="CBA entry ID.") + content = models.TextField(help_text="Textual content of the note.") + contributors = models.ManyToManyField( + Host, related_name="notes", help_text="`Host` IDs contributing to this note." + ) created_at = models.DateTimeField(auto_now_add=True) created_by = models.CharField(max_length=150) image = models.ForeignKey(Image, null=True, on_delete=models.CASCADE, related_name="notes") language = models.ManyToManyField(Language, blank=True, related_name="episodes") playlist = models.TextField(blank=True) - summary = models.TextField(blank=True) + summary = models.TextField(blank=True, help_text="Summary of the Note.") tags = models.JSONField(blank=True, default=list) timeslot = models.OneToOneField(TimeSlot, null=True, on_delete=models.SET_NULL, unique=True) - title = models.CharField(blank=True, default="", max_length=128) + title = models.CharField( + blank=True, default="", max_length=128, help_text="Title of the note." + ) topic = models.ManyToManyField(Topic, blank=True, related_name="episodes") updated_at = models.DateTimeField(auto_now=True, blank=True, null=True) updated_by = models.CharField(blank=True, default="", max_length=150) diff --git a/program/serializers.py b/program/serializers.py index 7e9619817551fd3b3ec6e8ddfe2b800706abc4cb..ac67e886150abb69d03fa14da240f9051dc242bd 100644 --- a/program/serializers.py +++ b/program/serializers.py @@ -263,9 +263,13 @@ class Thumbnail(TypedDict): class ImageSerializer(serializers.ModelSerializer): license_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=License.objects.all(), required=False, source="license" + allow_null=True, + queryset=License.objects.all(), + required=False, + source="license", + help_text="`License` ID of this image.", ) - ppoi = PPOIField(required=False) + ppoi = PPOIField(required=False, help_text="PPOI specifies the crop centerpoint of the image.") url = serializers.SerializerMethodField() @staticmethod @@ -330,11 +334,21 @@ class ImageRenderSerializer(serializers.Serializer): class HostSerializer(serializers.ModelSerializer): image_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=Image.objects.all(), required=False, source="image" + allow_null=True, + queryset=Image.objects.all(), + required=False, + source="image", + help_text="`Image` id of the host.", + ) + links = HostLinkSerializer( + many=True, required=False, help_text="Array of `HostLink` objects. Can be empty." ) - links = HostLinkSerializer(many=True, required=False) owner_ids = serializers.PrimaryKeyRelatedField( - allow_null=True, many=True, queryset=User.objects.all(), source="owners" + allow_null=True, + many=True, + queryset=User.objects.all(), + source="owners", + help_text="`User` id(s) identifying this host.", ) class Meta: @@ -479,39 +493,74 @@ class ShowLinkSerializer(serializers.ModelSerializer): class ShowSerializer(serializers.HyperlinkedModelSerializer): category_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=Category.objects.all(), source="category" + many=True, + queryset=Category.objects.all(), + source="category", + help_text="Array of `Category` IDs.", + ) + cba_series_id = serializers.IntegerField( + allow_null=True, required=False, help_text="CBA series ID." + ) + default_playlist_id = serializers.IntegerField( + allow_null=True, required=False, help_text="Default `Playlist` ID for this show." ) - cba_series_id = serializers.IntegerField(allow_null=True, required=False) - default_playlist_id = serializers.IntegerField(allow_null=True, required=False) funding_category_id = serializers.PrimaryKeyRelatedField( - queryset=FundingCategory.objects.all(), source="funding_category" + queryset=FundingCategory.objects.all(), + source="funding_category", + help_text="`FundingCategory` ID.", ) host_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=Host.objects.all(), source="hosts" + many=True, + queryset=Host.objects.all(), + source="hosts", + help_text="`Host` IDs of this show.", ) image_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=Image.objects.all(), required=False, source="image" + allow_null=True, + queryset=Image.objects.all(), + required=False, + source="image", + help_text="`Image` ID of this show.", ) language_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=Language.objects.all(), source="language" + many=True, + queryset=Language.objects.all(), + source="language", + help_text="`Language` IDs of this show.", ) - links = HostLinkSerializer(many=True, required=False) + links = HostLinkSerializer(many=True, required=False, help_text="Array of `Link` objects.") logo_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=Image.objects.all(), required=False, source="logo" + allow_null=True, + queryset=Image.objects.all(), + required=False, + source="logo", + help_text="`Image` ID of the logo of this show.", ) music_focus_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=MusicFocus.objects.all(), source="music_focus" + many=True, + queryset=MusicFocus.objects.all(), + source="music_focus", + help_text="Array of `MusicFocus` IDs.", ) owner_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=User.objects.all(), source="owners" + many=True, + queryset=User.objects.all(), + source="owners", + help_text="Array of `User` IDs owning this Show.", ) predecessor_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=Show.objects.all(), required=False, source="predecessor" + allow_null=True, + queryset=Show.objects.all(), + required=False, + source="predecessor", + help_text="`Show` ID that predeceeded this one.", ) topic_ids = serializers.PrimaryKeyRelatedField( - many=True, queryset=Topic.objects.all(), source="topic" + many=True, queryset=Topic.objects.all(), source="topic", help_text="Array of `Topic` IDs." + ) + type_id = serializers.PrimaryKeyRelatedField( + queryset=Type.objects.all(), source="type", help_text="Array of `Type` IDs." ) - type_id = serializers.PrimaryKeyRelatedField(queryset=Type.objects.all(), source="type") class Meta: model = Show @@ -840,12 +889,18 @@ class DryRunTimeSlotSerializer(serializers.Serializer): class ScheduleCreateUpdateRequestSerializer(serializers.Serializer): - schedule = ScheduleInRequestSerializer() + schedule = ScheduleInRequestSerializer(help_text="`Schedule` object.") solutions = serializers.DictField( - child=serializers.ChoiceField(SOLUTION_CHOICES), required=False + child=serializers.ChoiceField(SOLUTION_CHOICES), + required=False, + help_text="Array of solution choices.", + ) + notes = serializers.DictField( + child=serializers.IntegerField(), required=False, help_text="Array of `Note` objects." + ) + playlists = serializers.DictField( + child=serializers.IntegerField(), required=False, help_text="Array of `Playlist` IDs." ) - notes = serializers.DictField(child=serializers.IntegerField(), required=False) - playlists = serializers.DictField(child=serializers.IntegerField(), required=False) class ScheduleResponseSerializer(serializers.Serializer): @@ -870,10 +925,17 @@ class TimeSlotSerializer(serializers.ModelSerializer): note_id = serializers.SerializerMethodField() show_id = serializers.SerializerMethodField() schedule_id = serializers.PrimaryKeyRelatedField( - queryset=Schedule.objects.all(), required=False, source="schedule" + queryset=Schedule.objects.all(), + required=False, + source="schedule", + help_text="`Schedule` ID of this timeslot.", ) repetition_of_id = serializers.PrimaryKeyRelatedField( - allow_null=True, queryset=TimeSlot.objects.all(), required=False, source="repetition_of" + allow_null=True, + queryset=TimeSlot.objects.all(), + required=False, + source="repetition_of", + help_text="This timeslot is a repetition of `Timeslot` ID.", ) class Meta: @@ -934,9 +996,14 @@ class NoteSerializer(serializers.ModelSerializer): queryset=Host.objects.all(), required=False, source="contributors", + help_text="`Host` IDs that contributed to an episode.", ) image_id = serializers.PrimaryKeyRelatedField( - queryset=Image.objects.all(), required=False, allow_null=True, source="image" + queryset=Image.objects.all(), + required=False, + allow_null=True, + source="image", + help_text="`Image` ID.", ) language_ids = serializers.PrimaryKeyRelatedField( allow_null=True, @@ -944,15 +1011,24 @@ class NoteSerializer(serializers.ModelSerializer): queryset=Language.objects.all(), required=False, source="language", + help_text="Array of `Language` IDs.", ) - links = NoteLinkSerializer(many=True, required=False) - playlist_id = serializers.IntegerField(required=False) - tags = JSONSchemaField(tags_json_schema, required=False) + links = NoteLinkSerializer(many=True, required=False, help_text="Array of `Link` objects.") + playlist_id = serializers.IntegerField(required=False, help_text="Array of `Playlist` IDs.") + tags = JSONSchemaField(tags_json_schema, required=False, help_text="Tags of the Note.") timeslot_id = serializers.PrimaryKeyRelatedField( - queryset=TimeSlot.objects.all(), required=False, source="timeslot" + queryset=TimeSlot.objects.all(), + required=False, + source="timeslot", + help_text="`Timeslot` ID.", ) topic_ids = serializers.PrimaryKeyRelatedField( - allow_null=True, many=True, queryset=Topic.objects.all(), required=False, source="topic" + allow_null=True, + many=True, + queryset=Topic.objects.all(), + required=False, + source="topic", + help_text="Array of `Topic`IDs.", ) class Meta: