-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodels.py
More file actions
120 lines (97 loc) · 3.44 KB
/
models.py
File metadata and controls
120 lines (97 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
Data Models for the Users Microservice
"""
from typing import Any, Optional
import phonenumbers
from bson import ObjectId
from pydantic import BaseModel, field_validator
from pydantic_core import core_schema
# for handling mongo ObjectIds
class PyObjectId(ObjectId):
"""
Class for handling MongoDB document ObjectIds for 'id' fields in Models.
"""
@classmethod
def __get_pydantic_core_schema__(cls, source_type: Any, handler):
return core_schema.union_schema(
[
# check if it's an instance first before doing any further work
core_schema.is_instance_schema(ObjectId),
core_schema.no_info_plain_validator_function(cls.validate),
],
serialization=core_schema.to_string_ser_schema(),
)
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid ObjectId")
return ObjectId(v)
@classmethod
def __get_pydantic_json_schema__(cls, field_schema):
field_schema.update(type="string")
# user model
class User(BaseModel):
"""
Model for users information
This model defines the structure of a user's information.
Attributes:
uid (str): The user's unique identifier. Also has a validator to make
sure it is in lowercase.
img (Optional[str]): The user's profile picture URL. Defaults to None.
role (Optional[str]): The user's role. Defaults to `public` as
initially all users are public.
phone (Optional[str]): The user's phone number. Defaults to None.
"""
uid: str
img: Optional[str] = None
role: Optional[str] = "public"
phone: Optional[str] = None
# field validators
@field_validator("uid", mode="before")
@classmethod
# this method transforms user's uid to lowercase
def transform_uid(cls, v):
return v.lower()
@field_validator("role")
@classmethod
def constrain_role(cls, v) -> str:
"""
Makes sure the user's Role is either "public", "club", "cc", "slc",
or "slo".
Args:
v (str): The role to validate.
Returns:
(str): The validated role.
Raises:
ValueError: If the given role is not valid.
"""
role = v.lower()
if role not in ["public", "club", "cc", "slc", "slo"]:
raise ValueError("Invalid role!")
return role
@field_validator("phone")
@classmethod
def constrain_phone(cls, v) -> str | None:
"""
This method validates the given phone number according to the Indian
phone number format.
Args:
v (str): The phone number to validate.
Returns:
(str | None): The validated phone number without country code.
Raises:
ValueError: If the given phone number is not valid.
"""
if v is None or v == "":
return None
try:
phone = phonenumbers.parse(v, "IN")
if not phonenumbers.is_valid_number(phone):
raise ValueError("Invalid phone number!")
return phonenumbers.format_number(
phone, phonenumbers.PhoneNumberFormat.INTERNATIONAL
)
except phonenumbers.phonenumberutil.NumberParseException:
raise ValueError("Invalid phone number!")
except Exception as e:
raise ValueError(str(e))