class PrivateChatSchema(ma.Schema): """Class to serialize PrivateChat models.""" RESOURCE_NAME = "private_chat" COLLECTION_NAME = "private_chats" _id = ma.UUID(required=True, data_key="id") _primary_user = ma.Nested(UserSchema(), dump_only=True, data_key="primary_user") _secondary_user = ma.Nested(UserSchema(), dump_only=True, data_key="secondary_user") resource_type = ma.Str(dump_only=True, default="PrivateChat") # Links messages_url = ma.URLFor("api.get_private_chat_messages", private_chat_id="<_id>") @post_load def convert_uuid_to_hex(self, data, **kwargs): """Convert all UUID fields to their 32-character hexadecimal equivalent.""" for key in data: value = data[key] if isinstance(value, uuid.UUID): data[key] = data[key].hex return data
class GroupChatSchema(ma.Schema): """Class for serializing and deserializing GroupChat models.""" RESOURCE_NAME = "group_chat" COLLECTION_NAME = "group_chats" class Meta: unknown = EXCLUDE _id = ma.UUID(required=True, data_key="id") _community_id = ma.UUID(required=True, data_key="community_id") name = ma.Str(required=True, validate=validate.Length(min=1, max=32)) description = ma.Str(required=True, validate=validate.Length(min=1, max=140)) resource_type = ma.Str(default="GroupChat", dump_only=True) # Links self_url = ma.URLFor( "api.get_community_group_chat", community_id="<_community_id>", group_chat_id="<_id>" ) messages_url = ma.URLFor("api.get_group_chat_messages", group_chat_id="<_id>") community_url = ma.URLFor("api.get_community", community_id="<_id>") members_url = ma.URLFor("api.get_community_group_chat_members", community_id="<_community_id>", group_chat_id="<_id>") @post_load def convert_uuid_to_hex(self, data, **kwargs): """Convert all UUID fields to their 32-character hexadecimal equivalent.""" for key in data: value = data[key] if isinstance(value, uuid.UUID): data[key] = data[key].hex return data @pre_load def strip_unwanted_fields(self, data, many, **kwargs): """Remove unwanted fields from the input data before deserialization.""" unwanted_fields = ["resource_type"] for field in unwanted_fields: if field in data: data.pop(field) return data
class CommunitySchema(ma.Schema): """Class to serialize and deserialize Community models.""" COLLECTION_NAME = "communities" RESOURCE_NAME = "community" class Meta: unknown = EXCLUDE _id = ma.UUID(data_key="id", dump_only=True) name = ma.Str(required=True, validate=validate.Length(min=1, max=64)) description = ma.Str(required=True, validate=validate.Length(min=1, max=280)) topic = EnumField(CommunityTopic) avatar = ma.Nested(ImageSchema, dump_only=True) cover_photo = ma.Nested(ImageSchema, dump_only=True) location = ma.Nested(LocationSchema, required=True) _founder_id = ma.UUID(dump_only=True, data_key="founder_id") _created_at = ma.DateTime(data_key="founded_on", dump_only=True) # defaults to ISO 8601 resource_type = ma.Str(default="Community", dump_only=True) # Links self_url = ma.URLFor("api.get_community", community_id="<_id>") founder_url = ma.URLFor("api.get_user", user_id="<_founder_id>") members_url = ma.URLFor("api.get_community_members", community_id="<_id>") group_chats_url = ma.URLFor("api.get_community_group_chats", community_id="<_id>") @pre_load def strip_unwanted_fields(self, data, many, **kwargs): """Remove unwanted fields from the input data before deserialization.""" unwanted_fields = ["resource_type"] for field in unwanted_fields: if field in data: data.pop(field) return data
class UserSchema(ma.Schema): """Class to serialize and deserialize User models.""" COLLECTION_NAME = "users" RESOURCE_NAME = "user" class Meta: unknown = EXCLUDE _id = ma.UUID(data_key="id", dump_only=True) username = ma.Str(required=True, validate=validate.Length(min=1, max=32)) name = ma.Str(required=True, validate=validate.Length(min=1, max=32)) email = ma.Email(required=True, validate=validate.Length(min=1, max=32)) _created_at = ma.DateTime(data_key="joined_on", dump_only=True) # defaults to ISO 8601 last_seen_at = ma.DateTime(dump_only=True) # defaults to ISO 8601 password = ma.Str(required=True, load_only=True) bio = ma.Str(validate=validate.Length(max=280)) resource_type = ma.Str(default="User", dump_only=True) location = ma.Nested(LocationSchema, required=True) avatar = ma.Nested(ImageSchema, dump_only=True) cover_photo = ma.Nested(ImageSchema, dump_only=True) # links self_url = ma.URLFor("api.get_user", user_id="<_id>") communities_url = ma.URLFor("api.get_user_communities", user_id="<_id>") notifications_url = ma.URLFor("api.get_user_notifications", user_id="<_id>") private_chats_url = ma.URLFor("api.get_user_private_chats", user_id="<_id>") group_chats_url = ma.URLFor("api.get_user_group_chats", user_id="<_id>") @pre_load def strip_unwanted_fields(self, data, many, **kwargs): """Remove unwanted fields from the input data before deserialization.""" unwanted_fields = ["resource_type"] for field in unwanted_fields: if field in data: data.pop(field) return data @post_dump(pass_original=True) def inject_extra_fields(self, data, original_model, **kwargs): """Post processing method to inject extra fields into the serialized data. """ if hasattr(original_model, "role"): data["is_admin"] = original_model.is_admin() return data
class GroupChatUrlParamsSchema(UrlParamsSchema): """Class to parse and validate information from Group Chat url parameters.""" class Meta: unknown = EXCLUDE community_id = ma.UUID(required=True) @post_load def convert_uuid_to_hex(self, data, **kwargs): """Convert all UUID fields to their 32-character hexadecimal equivalent.""" for key in data: value = data[key] if isinstance(value, uuid.UUID): data[key] = data[key].hex return data
class NotificationSchema(ma.Schema): """Class to serialize and deserialize notification models. """ RESOURCE_NAME = "notification" COLLECTION_NAME = "notifications" class Meta: unknown = EXCLUDE _id = ma.Str(required=True, data_key="id", dump_only=True) _user_id = ma.UUID(required=True, data_key="user_id", dump_only=True) _notification_type = EnumField(NotificationType, required=True, data_key="notification_type", dump_only=True) _message = ma.Str(required=True, data_key="message", validate=validate.Length(min=1, max=64), dump_only=True) _target_url = ma.URL(required=True, data_key="target_url", dump_only=True) _created_at = ma.DateTime(data_key="timestamp", dump_only=True) # defaults to ISO 8601 _read = ma.Boolean(data_key="read") _seen = ma.Boolean(data_key="seen") resource_type = ma.Str(default="Notification", dump_only=True) @validates_schema def validate_read_and_seen(self, data, **kwargs): """Raise a ValidationError if both read and seen aren't present in the data on load. """ if "_read" not in data and "_seen" not in data: raise ValidationError( "Please provide at least one field to update. Valid fields to update are: read, seen" ) return data @pre_load def strip_unwanted_fields(self, data, many, **kwargs): """Remove unwanted fields from the input data before deserialization.""" unwanted_fields = ["resource_type"] for field in unwanted_fields: if field in data: data.pop(field) return data
from flask import current_app, url_for, g from app.api import api from app.repositories import database_repository from app.repositories.exceptions import ( DatabaseException, NotFoundException, UniqueConstraintException, ) from app.schemas import UrlParamsSchema, PrivateChatMessageSchema, PrivateChatSchema from app.decorators.views import handle_request, handle_response from app.decorators.auth import permission_required from app.models import RolePermission, PrivateChat, MessageType from app.extensions import ma PrivateChatGeneratedSchema = ma.Schema.from_dict( {"other_user_id": ma.UUID(required=True)}) @api.route("/private_chats/<private_chat_id>/messages") @handle_request(UrlParamsSchema()) @handle_response(PrivateChatMessageSchema(many=True)) def get_private_chat_messages(url_params, private_chat_id): """Return a list of private chat message resources.""" per_page = url_params.get("per_page", current_app.config["RESULTS_PER_PAGE"]) cursor = url_params.get("next_cursor") private_chat = database_repository.get_private_chat(private_chat_id) if not private_chat: return {"error": "Private chat not found"}, HTTPStatus.NOT_FOUND if not private_chat.is_member(g.current_user.id): return {