"""Authentication-related API schemas.""" from datetime import datetime from typing import List, Optional from ninja import ModelSchema, Schema from apps.users.models import User from apps.blog.permissions import can_access_blog_admin, can_review_blog_posts, can_write_blog_posts from core.media import PREVIEW_VARIANT, THUMBNAIL_VARIANT, derivative_url class UserRegistrationSchema(Schema): username: str mobile: str code: str password: str email: Optional[str] = None first_name: Optional[str] = None last_name: Optional[str] = None university: Optional[str] = None student_id: Optional[str] = None year_of_study: Optional[int] = None major: Optional[str] = None class UserLoginSchema(Schema): identifier: str password: str class UserOtpLoginSchema(Schema): mobile: str code: str class RegisterOtpVerifySchema(Schema): mobile: str code: str class OtpSendSchema(Schema): mobile: str mode: str class MobileOtpSendSchema(Schema): mobile: str class MobileOtpVerifySchema(Schema): mobile: str code: str class GoogleFlowSchema(Schema): flow: str class GoogleClaimVerifySchema(Schema): flow: str code: str class GoogleCompleteSchema(Schema): flow: str mobile: str username: Optional[str] = None student_id: Optional[str] = None year_of_study: Optional[int] = None major: Optional[str] = None university: Optional[str] = None first_name: Optional[str] = None last_name: Optional[str] = None class GoogleFlowResponseSchema(Schema): status: str email: Optional[str] = None first_name: Optional[str] = None last_name: Optional[str] = None avatar_url: Optional[str] = None resolution: Optional[str] = None mobile: Optional[str] = None mobile_hint: Optional[str] = None detail: Optional[str] = None access_token: Optional[str] = None refresh_token: Optional[str] = None class UserProfileSchema(ModelSchema): profile_picture: Optional[str] = None profile_picture_thumbnail_url: Optional[str] = None profile_picture_preview_url: Optional[str] = None student_id: Optional[str] = None major: Optional[str] = None university: Optional[str] = None mobile: Optional[str] = None requires_mobile_verification: bool has_google_link: bool can_access_blog_admin: bool can_write_blog_posts: bool can_review_blog_posts: bool class Meta: model = User fields = [ "id", "username", "email", "mobile", "first_name", "last_name", "student_id", "year_of_study", "major", "university", "bio", "date_joined", "is_email_verified", "is_mobile_verified", "is_active", "is_staff", "is_superuser", "is_deleted", "deleted_at", ] @staticmethod def resolve_major(obj): return obj.get_major_display() @staticmethod def resolve_university(obj): return obj.get_university_display() @staticmethod def resolve_requires_mobile_verification(obj): return obj.requires_mobile_verification @staticmethod def resolve_has_google_link(obj): return obj.has_google_link @staticmethod def resolve_can_access_blog_admin(obj): return can_access_blog_admin(obj) @staticmethod def resolve_can_write_blog_posts(obj): return can_write_blog_posts(obj) @staticmethod def resolve_can_review_blog_posts(obj): return can_review_blog_posts(obj) @staticmethod def resolve_profile_picture(obj, context): request = context["request"] if obj.profile_picture and hasattr(obj.profile_picture, "url"): return request.build_absolute_uri(obj.profile_picture.url) return None @staticmethod def resolve_profile_picture_thumbnail_url(obj, context): request = context["request"] url = derivative_url(obj.profile_picture, THUMBNAIL_VARIANT) return request.build_absolute_uri(url) if url else None @staticmethod def resolve_profile_picture_preview_url(obj, context): request = context["request"] url = derivative_url(obj.profile_picture, PREVIEW_VARIANT) return request.build_absolute_uri(url) if url else None class UserListSchema(ModelSchema): major: Optional[str] = None university: Optional[str] = None mobile: Optional[str] = None profile_picture: Optional[str] = None profile_picture_thumbnail_url: Optional[str] = None profile_picture_preview_url: Optional[str] = None student_id: Optional[str] = None year_of_study: Optional[int] = None bio: Optional[str] = None is_email_verified: bool is_mobile_verified: bool is_deleted: bool deleted_at: Optional[datetime] = None can_access_blog_admin: bool can_write_blog_posts: bool can_review_blog_posts: bool class Meta: model = User fields = [ "id", "username", "email", "mobile", "first_name", "last_name", "student_id", "year_of_study", "bio", "is_active", "is_staff", "is_superuser", "date_joined", "major", "university", "is_email_verified", "is_mobile_verified", "is_deleted", "deleted_at", ] @staticmethod def resolve_major(obj): return obj.get_major_display() @staticmethod def resolve_university(obj): return obj.get_university_display() @staticmethod def resolve_can_access_blog_admin(obj): return can_access_blog_admin(obj) @staticmethod def resolve_can_write_blog_posts(obj): return can_write_blog_posts(obj) @staticmethod def resolve_can_review_blog_posts(obj): return can_review_blog_posts(obj) @staticmethod def resolve_profile_picture(obj, context): request = context["request"] if obj.profile_picture and hasattr(obj.profile_picture, "url"): return request.build_absolute_uri(obj.profile_picture.url) return None @staticmethod def resolve_profile_picture_thumbnail_url(obj, context): request = context["request"] url = derivative_url(obj.profile_picture, THUMBNAIL_VARIANT) return request.build_absolute_uri(url) if url else None @staticmethod def resolve_profile_picture_preview_url(obj, context): request = context["request"] url = derivative_url(obj.profile_picture, PREVIEW_VARIANT) return request.build_absolute_uri(url) if url else None class AuthorizationRoleSchema(Schema): key: str label: str description: str enabled: bool = False locked: bool = False class UserAuthorizationSchema(Schema): id: int username: str email: Optional[str] = None mobile: Optional[str] = None first_name: str last_name: str is_active: bool is_staff: bool is_superuser: bool groups: List[str] roles: List[AuthorizationRoleSchema] class UserAuthorizationUpdateSchema(Schema): is_staff: bool = False groups: List[str] = [] class UserUpdateSchema(Schema): email: Optional[str] = None first_name: Optional[str] = None last_name: Optional[str] = None bio: Optional[str] = None year_of_study: Optional[int] = None major: Optional[str] = None university: Optional[str] = None student_id: Optional[str] = None class TokenSchema(Schema): access_token: str refresh_token: str token_type: str = "bearer" class TokenRefreshIn(Schema): refresh_token: str class PasswordResetSchema(Schema): mobile: str code: str new_password: str class UsernameCheckSchema(Schema): exists: bool class MobileLookupSchema(Schema): exists: bool has_password: bool class OtpSendResponseSchema(Schema): message: str expires_in_seconds: int expires_at: datetime