-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutations.py
More file actions
307 lines (243 loc) · 8.98 KB
/
mutations.py
File metadata and controls
307 lines (243 loc) · 8.98 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
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
"""
Mutation Resolvers
"""
import os
import re
import strawberry
from fastapi.encoders import jsonable_encoder
from db import ccdb, docsstoragedb
from mailing import send_mail
from mailing_templates import (
APPLICANT_CONFIRMATION_BODY,
APPLICANT_CONFIRMATION_SUBJECT,
CC_APPLICANT_CONFIRMATION_BODY,
CC_APPLICANT_CONFIRMATION_SUBJECT,
)
from models import CCRecruitment, StorageFile
# import all models and types
from otypes import (
CCRecruitmentInput,
Info,
MailInput,
StorageFileInput,
StorageFileType,
)
from utils import get_curr_time_str
inter_communication_secret_global = os.getenv("INTER_COMMUNICATION_SECRET")
# sample mutation
@strawberry.mutation
async def sendMail(
info: Info,
mailInput: MailInput,
inter_communication_secret: str | None = None,
) -> bool:
"""
Resolver that initiates the sending of an email.
Args:
info (otypes.Info): contains the user's context information.
mailInput (otypes.MailInput): The input data for sending an email.
inter_communication_secret (str): The secret key
for inter-communication. Defaults to None.
Returns:
(bool): True if the email is sent successfully, False otherwise.
Raises:
Exception: Not logged in!
Exception: Not Authenticated to access this API!!
"""
user = info.context.user
if not user:
raise Exception("Not logged in!")
if user.get("role", None) not in ["cc", "club", "slo", "slc", "email_bot"]:
raise Exception("Not Authenticated to access this API!!")
if inter_communication_secret != inter_communication_secret_global:
raise Exception("Authentication Error! Invalid secret!")
mail_input = jsonable_encoder(mailInput.to_pydantic())
if mail_input["uid"] is None:
mail_input["uid"] = user["uid"]
# send mail as background task
info.context.background_tasks.add_task(
send_mail,
mail_input["subject"],
mail_input["body"],
mail_input["to_recipients"],
mail_input["cc_recipients"],
None,
mail_input["html_body"],
)
# send_mail(mail_input["subject"], mail_input["body"],
# mail_input["to_recipients"], mail_input["cc_recipients"]):
# created_sample = Mails.model_validate(
# db.mails.find_one({"_id": 0}, {"_id": 0}))
# else:
# # add to database
# created_id = db.mails.insert_one(mail_input).inserted_id
#
# # query from database
# created_sample = Mails.model_validate(
# db.mails.find_one({"_id": created_id}, {"_id": 0}))
#
# return MailReturnType.from_pydantic(created_sample)
return True
@strawberry.mutation
async def ccApply(ccRecruitmentInput: CCRecruitmentInput, info: Info) -> bool:
"""
This method is used to apply for CC
This method is invoked when a user applies for CC.
It send mails to the user and the CC admins regarding the application.
Args:
ccRecruitmentInput (otypes.CCRecruitmentInput): The input data while
applying for CC.
info (otypes.Info): contains the user's context information.
Returns:
(bool): True if the application is successful, False otherwise.
Raises:
Exception: Not logged in!
Exception: Not Authenticated to access this API!!
Exception: You have already applied for CC!!
"""
user = info.context.user
if not user:
raise Exception("Not logged in!")
if user.get("role", None) not in ["public"]:
raise Exception("Not Authenticated to access this API!!")
cc_recruitment_input = jsonable_encoder(ccRecruitmentInput.to_pydantic())
curr_year = int(get_curr_time_str()[:4])
# Check if the user has already applied
if await ccdb.find_one(
{"email": cc_recruitment_input["email"], "apply_year": curr_year}
):
raise Exception("You have already applied for CC!!")
cc_recruitment_input["apply_year"] = curr_year
# add to database
created_id = (await ccdb.insert_one(cc_recruitment_input)).inserted_id
created_sample = CCRecruitment.model_validate(
await ccdb.find_one({"_id": created_id})
)
# Send emails
info.context.background_tasks.add_task(
send_mail,
APPLICANT_CONFIRMATION_SUBJECT.safe_substitute(),
APPLICANT_CONFIRMATION_BODY.safe_substitute(),
[created_sample.email],
)
info.context.background_tasks.add_task(
send_mail,
CC_APPLICANT_CONFIRMATION_SUBJECT.safe_substitute(),
CC_APPLICANT_CONFIRMATION_BODY.safe_substitute(
uid=created_sample.uid,
email=created_sample.email,
teams=", ".join(created_sample.teams),
why_this_position=created_sample.why_this_position,
why_cc=created_sample.why_cc,
good_fit=created_sample.good_fit,
ideas1=created_sample.ideas1,
ideas=created_sample.ideas,
other_bodies=created_sample.other_bodies,
design_experience=created_sample.design_experience or "N/A",
),
["clubs@iiit.ac.in"],
)
return True
# StorageFile related mutations
@strawberry.mutation
async def createStorageFile(
details: StorageFileInput, info: Info
) -> StorageFileType:
"""
Enables CC to create of a new storagefile
Args:
details (otypes.StorageFileInput): The details of the storagefile to be
created.
info (otypes.Info): contains the user's context information.
Returns:
(otypes.StorageFileType): The created storagefile.
Raises:
ValueError: You do not have permission to access this resource.
ValueError: A storagefile already exists with this name.
"""
user = info.context.user
if user is None or user.get("role") != "cc":
raise ValueError("You do not have permission to access this resource.")
storagefile = StorageFile(
title=details.title,
filename=details.filename,
filetype=details.filetype,
)
# Check if any storagefile with same title already exists
if await docsstoragedb.find_one(
{"title": {"$regex": f"^{re.escape(details.title)}$", "$options": "i"}}
):
raise ValueError("A storagefile already exists with this name.")
created_id = (
await docsstoragedb.insert_one(jsonable_encoder(storagefile))
).inserted_id
created_storagefile = await docsstoragedb.find_one({"_id": created_id})
return StorageFileType.from_pydantic(
StorageFile.model_validate(created_storagefile)
)
@strawberry.mutation
async def updateStorageFile(id: str, version: int, info: Info) -> bool:
"""
Enables CC to update an existing storagefile
Args:
id (str): The id of the storagefile to be updated.
version (int): The new version of the storagefile.
info (otypes.Info): contains the user's context information.
Returns:
(bool): True if the storagefile is updated successfully, False
otherwise.
Raises:
ValueError: You do not have permission to access this resource.
ValueError: StorageFile not found.
"""
user = info.context.user
if user is None or user.get("role") != "cc":
raise ValueError("You do not have permission to access this resource.")
storagefile = await docsstoragedb.find_one({"_id": id})
if storagefile is None:
raise ValueError("StorageFile not found.")
updated_storagefile = StorageFile(
_id=id,
title=storagefile["title"],
filename=storagefile["filename"],
filetype=storagefile["filetype"],
modified_time=get_curr_time_str(),
creation_time=storagefile["creation_time"],
latest_version=version,
)
await docsstoragedb.find_one_and_update(
{"_id": id}, {"$set": jsonable_encoder(updated_storagefile)}
)
return True
@strawberry.mutation
async def deleteStorageFile(id: str, info: Info) -> bool:
"""
Enables CC to delete an existing storagefile
Args:
id (str): The id of the storagefile to be deleted.
info (otypes.Info): contains the user's context information.
Returns:
(bool): True if the storagefile is deleted successfully, False
otherwise.
Raises:
ValueError: You do not have permission to access this resource.
ValueError: StorageFile not found.
"""
user = info.context.user
if user is None or user.get("role") != "cc":
raise ValueError("You do not have permission to access this resource.")
storagefile = await docsstoragedb.find_one({"_id": id})
if storagefile is None:
raise ValueError("StorageFile not found.")
# delete the file from storage
# delete_file(storagefile["filename"])
await docsstoragedb.delete_one({"_id": id})
return True
# register all mutations
mutations = [
sendMail,
ccApply,
createStorageFile,
updateStorageFile,
deleteStorageFile,
]