-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodels.py
227 lines (189 loc) · 6.8 KB
/
models.py
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
from datetime import datetime
from enum import Enum
from typing import Annotated, Any, List
import strawberry
from bson import ObjectId
from pydantic import (
BaseModel,
BeforeValidator,
ConfigDict,
EmailStr,
Field,
HttpUrl,
TypeAdapter,
field_validator,
)
from pydantic_core import core_schema
from pytz import timezone
"""
Annotated type and validator for HTTP URLs to be stored as strings.
"""
http_url_adapter = TypeAdapter(HttpUrl)
HttpUrlString = Annotated[
str,
BeforeValidator(
lambda value: str(http_url_adapter.validate_python(value))
),
]
def create_utc_time():
"""
Returns the current time according to UTC timezone.
"""
return datetime.now(timezone("UTC"))
# 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")
def iiit_email_only(v: str) -> str:
"""
Validates emails according to the valid forms.
Args:
v (str): The Email to be validated.
Raises:
ValueError: If email is not valid.
Returns:
str: Valid Email.
"""
valid_domains = [
"@iiit.ac.in",
"@students.iiit.ac.in",
"@research.iiit.ac.in",
]
if any(valid_domain in v for valid_domain in valid_domains):
return v.lower()
raise ValueError("Official iiit emails only.")
def current_year() -> int:
"""Returns the current year."""
return datetime.now().year
@strawberry.enum
class EnumStates(str, Enum):
"""Enum for state of the club."""
active = "active"
deleted = "deleted"
@strawberry.enum
class EnumCategories(str, Enum):
"""Enum for category of the club."""
cultural = "cultural"
technical = "technical"
affinity = "affinity"
admin = "admin"
body = "body"
other = "other"
class Social(BaseModel):
"""
Model for storing social handles of a Club
Attributes:
website (HttpUrlString | None): Club Website URL. Defaults to None.
instagram (HttpUrlString | None): Club Instagram handle.
Defaults to None.
facebook (HttpUrlString | None): Club Facebook. Defaults to None.
youtube (HttpUrlString | None): Club YouTube handle. Defaults to None.
twitter (HttpUrlString | None): Club Twitter handle. Defaults to None.
linkedin (HttpUrlString | None): Club LinkedIn handle.
Defaults to None.
discord (HttpUrlString | None): Club Discord handle. Defaults to None.
whatsapp (HttpUrlString | None): Club WhatsApp handle.
Defaults to None.
other_links (List[HttpUrlString]): List of other social handles
and URLs
"""
website: HttpUrlString | None = None
instagram: HttpUrlString | None = None
facebook: HttpUrlString | None = None
youtube: HttpUrlString | None = None
twitter: HttpUrlString | None = None
linkedin: HttpUrlString | None = None
discord: HttpUrlString | None = None
whatsapp: HttpUrlString | None = None
other_links: List[HttpUrlString] = Field([]) # Type and URL
@field_validator("other_links")
@classmethod
def validate_unique_links(cls, value):
if len(value) != len(set(value)):
raise ValueError("Duplicate URLs are not allowed in 'other_links'")
return value
class Club(BaseModel):
"""
Model for storing Club details.
Attributes:
id (PyObjectId): Unique ObjectId of the document of the Club.
cid (str): the Club ID.
code (str): Unique Short Code of Club.
state (EnumStates): State of the Club.
category (EnumCategories): Category of the Club.
student_body (bool): Is this a Student Body?
name (str): Name of the Club.
email (EmailStr): Email of the Club.
logo (str | None): Club Official Logo. Defaults to None.
banner (str | None): Club Long Banner. Defaults to None.
banner_square (str | None): Club Square Banner. Defaults to None.
tagline (str | None): Tagline of the Club. Defaults to None.
description (str | None): Club Description. Defaults to None.
socials (Social): Social Handles of the Club.
created_time (datetime): Time of creation of the Club.
updated_time (datetime): Time of last update to the Club.
"""
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
cid: str = Field(..., description="Club ID")
code: str = Field(
...,
description="Unique Short Code of Club",
max_length=15,
min_length=2,
) # equivalent to club id = short name
state: EnumStates = EnumStates.active
category: EnumCategories = EnumCategories.other
name: str = Field(..., min_length=5, max_length=100)
email: EmailStr = Field(...) # Optional but required
logo: str | None = Field(None, description="Club Official Logo pic URL")
banner: str | None = Field(None, description="Club Long Banner pic URL")
banner_square: str | None = Field(
None, description="Club Square Banner pic URL"
)
tagline: str | None = Field(None, min_length=2, max_length=200)
description: str | None = Field(
"No Description Provided!",
max_length=9999,
description="Club Description",
)
socials: Social = Field({}, description="Social Profile Links")
created_time: datetime = Field(
default_factory=create_utc_time, frozen=True
)
updated_time: datetime = Field(default_factory=create_utc_time)
# Validator
@field_validator("email", mode="before")
def _check_email(cls, v):
return iiit_email_only(v)
model_config = ConfigDict(
populate_by_name=True,
arbitrary_types_allowed=True,
json_encoders={ObjectId: str},
str_max_length=10000,
validate_assignment=True,
validate_default=True,
validate_return=True,
extra="forbid",
str_strip_whitespace=True,
)
# TODO: ADD CLUB SUBSCRIPTION MODEL - v2
# ADD Descriptions for non-direct fields