from marshmallow import EXCLUDE, Schema, ValidationError, fields, validates_schema from src.config import DATETIME_FORMAT from src.core.schemas import ApplicationRequestSchema from src.enums import FieldCopyMode, MusicService, ServiceType # ================= Base schemas ================= class InsertMediaSchema(Schema): mediaId = fields.String(attribute="media_id") insertPosition = fields.Integer(attribute="insert_position") class BaseSchema(Schema): applicationId = fields.Integer(attribute="application_id") fromPlaylistId = fields.String(attribute="from_playlist_id") fromServiceType = fields.Enum(ServiceType, by_value=True, attribute="from_service_type") fromMusicServiceId = fields.Enum(MusicService, by_value=True, attribute="from_music_service") toPlaylistId = fields.String(attribute="to_playlist_id") toServiceAccountId = fields.Integer(attribute="to_service_account_id") title = fields.String(allow_none=True) description = fields.String(allow_none=True) titleCopyMode = fields.Enum(FieldCopyMode, by_value=True, attribute="title_copy_mode") descriptionCopyMode = fields.Enum(FieldCopyMode, by_value=True, attribute="description_copy_mode") active = fields.Boolean() @validates_schema def validate_numbers(self, data, **kwargs): if data.get("from_playlist_id") == data.get("to_playlist_id"): raise ValidationError("fromPlaylistId and toPlaylistId can't be identical") class LogSchema(Schema): time = fields.DateTime(attribute="latest_log.timestamp", format=DATETIME_FORMAT, dump_default=None) madeChange = fields.Boolean(attribute="latest_log.made_change", dump_default=None) addedTracks = fields.Integer(attribute="latest_log.added_tracks", dump_default=None) deletedTracks = fields.Integer(attribute="latest_log.deleted_tracks", dump_default=None) deletedDuplicates = fields.Integer(attribute="latest_log.deleted_duplicates", dump_default=None) # I have no idea why "target_track_count" become "syncedTrackCount" syncedTrackCount = fields.Integer(attribute="latest_log.target_track_count", dump_default=None) errorText = fields.String(attribute="latest_log.error_text", dump_default=None) triggeredManually = fields.Boolean(attribute="latest_log.triggered_manually", dump_default=None) errorType = fields.String(attribute="latest_log.error_type", dump_default=None) class ServiceTypeSchema(Schema): toServiceType = fields.Enum(ServiceType, by_value=True, attribute="service_account.service_type") class SyncSchema(BaseSchema): id = fields.Integer() lastUpdated = fields.DateTime(attribute="updated_at", format=DATETIME_FORMAT) createdAt = fields.DateTime(attribute="created_at", format=DATETIME_FORMAT) sourceTitle = fields.String(attribute="source_title") sourceImage = fields.String(attribute="source_image") sourceTrackCount = fields.Integer(attribute="source_track_count") synchronizedTrackCount = fields.Integer(attribute="synchronized_track_count") insertMedia = fields.Nested(InsertMediaSchema, many=True, attribute="insert_media") sourceServiceAccountId = fields.String(attribute="source_service_account_id") sourceServiceAccountName = fields.String(attribute="source_service_account_name") toPlaylistTitle = fields.String(attribute="to_playlist_title") toPlaylistImage = fields.String(attribute="to_playlist_image") # ================= Request schemas ================= class SyncRequestSchema(ApplicationRequestSchema): sync_id = fields.Integer(required=True) class CreatePlaylistSyncRequestSchema(BaseSchema): pass class UpdatePlaylistSyncRequestSchema(BaseSchema): class Meta: # Frontend sends the whole object, but we only need "Base" fields unknown = EXCLUDE # ================= Response schemas ================= class GetPlaylistSyncResponseSchema(SyncSchema, LogSchema, ServiceTypeSchema): pass class ListPlaylistSyncResponseSchema(GetPlaylistSyncResponseSchema): pass class CreatePlaylistSyncResponseSchema(SyncSchema): appendTrackList = fields.Boolean(attribute="append_track_list") error = fields.Boolean() class UpdatePlaylistSyncResponseSchema(CreatePlaylistSyncResponseSchema): pass