from apollo_utils.service.schemas.base import RequestSchema from apollo_utils.service.schemas.fields.list import SplitUniqueListField from apollo_utils.service.schemas.mixins.pagination import PaginationResponseMixin from marshmallow import Schema, ValidationError, fields, post_load, pre_load, validate, validates_schema from server.constants.messages import FEED_MESSAGE_SEARCH_SPACE_ADD_CHARACTERS, FeedMessagesFilterSubject from server.schemas.pagination import HighLimitPaginationMixin # todo move this logic to utils-pkg class SingleArgOnlyMixin: _id_fields = {"message_id", "related_id"} @pre_load def validate_single_argument(self, data, **kwargs): """Ensure that exactly one ID is provided.""" keys = self._id_fields & set(data.keys()) if len(keys) != 1: raise ValidationError("Provide one and only one ID of {}.".format(", ".join(self._id_fields))) return data class UsersMessagesFeed: class Request(HighLimitPaginationMixin, RequestSchema): status = fields.Boolean(data_key="is_new") subject = SplitUniqueListField(fields.String, data_key="type", missing=FeedMessagesFilterSubject.values()) search = fields.String(validates=validate.Length(min=1, max=50), required=False, missing=None) @post_load def reformat_search(self, data, *args, **kwargs): if data["search"]: escaped_query = "" for char in data["search"].lower().strip(): escaped_query += f" {char}" if char in FEED_MESSAGE_SEARCH_SPACE_ADD_CHARACTERS else char data["search"] = [f"%{i}%" for i in escaped_query.split()] return data class Response(PaginationResponseMixin, Schema): class FeedMessageItem(Schema): id = fields.Integer() topic = fields.String() vendor = fields.String() track_id = fields.String() date = fields.DateTime() time_delta = fields.Integer() artist_name = fields.String() track_name = fields.String() position = fields.Integer() target = fields.String() isrc = fields.String() country_code = fields.String() playlist_id = fields.String() playlist_name = fields.String() playlist_image_url = fields.String() is_new = fields.Boolean() title = fields.String() message = fields.String() change = fields.Integer() items = fields.List(fields.Nested(FeedMessageItem)) class UsersMessagesFeedView: class Request(RequestSchema, SingleArgOnlyMixin): message_id = fields.Integer(required=False) related_id = fields.Integer(required=False) @validates_schema def validate_data(self, data, **kwargs): message_id = data.get("message_id") related_id = data.get("related_id") if all([message_id, related_id]): raise ValidationError("Only one of 'message_id' or 'related_id' should be passed.") if not any([message_id, related_id]): raise ValidationError("One of 'message_id' or 'related_id' should be passed.") class Response(Schema): pass