1- from fastapi import FastAPI , HTTPException
1+ from fastapi import FastAPI , HTTPException , Request
2+ from fastapi .responses import RedirectResponse
23import firebase_admin
34from firebase_admin import credentials , db , auth
45import phonenumbers
78from datetime import datetime
89import os
910from dotenv import load_dotenv
11+ import random
12+ import string
1013
1114load_dotenv ()
1215
2730firebase_admin .initialize_app (cred , {"databaseURL" : os .getenv ("DATABASE_URL" )})
2831
2932ref = db .reference ("/" )
30- agenda_ref = ref .child ('agenda ' )
33+ agenda_ref = ref .child ('agendas ' )
3134
3235def to_e164_br (phone_number ):
3336 try :
@@ -46,6 +49,30 @@ def timestamp_formatado(timestamp):
4649 except ValueError :
4750 raise HTTPException (status_code = 400 , detail = "Formato de timestamp inválido. Use ISO 8601 (ex: '2025-06-27T14:00:00')" )
4851
52+ def check_uid_exists (uid : str ):
53+ try :
54+ user = auth .get_user (uid )
55+ print (f"✅ User exists: { user .uid } , email: { user .email } " )
56+ return True
57+ except auth .UserNotFoundError :
58+ print ("❌ No user found with that UID." )
59+ return False
60+ except Exception as e :
61+ print (f"⚠️ Error: { e } " )
62+ return False
63+
64+ def generate_random_invite_url (length : int = 12 ) -> str :
65+ chars = string .ascii_letters + string .digits # A-Z, a-z, 0-9
66+ return '' .join (random .choices (chars , k = length ))
67+
68+ STANDARD_RESPONSES = {
69+ 400 : {"description" : "Bad Request" },
70+ 401 : {"description" : "Unauthorized" },
71+ 403 : {"description" : "Forbidden" },
72+ 404 : {"description" : "Not Found" },
73+ 500 : {"description" : "Internal Server Error" },
74+ }
75+
4976tags_metadata = [
5077 {
5178 "name" : "Usuários" ,
@@ -63,34 +90,69 @@ def timestamp_formatado(timestamp):
6390def read_root ():
6491 return {"Hello" : "World" }
6592
66- @app .get ("/testFirebase" )
93+ @app .get ("/testFirebase" , responses = STANDARD_RESPONSES )
6794def testar_o_firebase ():
6895 try :
6996 if ref .get ():
7097 message = "Conectado com successo ao Firebase"
98+ return {"message" : message }
7199 except Exception as e :
72- message = f"Falha ao se conectar com o Firebase: { str (e )} "
73- return {"message" : message }
100+ raise HTTPException (status_code = 500 , detail = f"Falha ao se conectar com o Firebase: { str (e )} " )
101+
102+ from fastapi import APIRouter
103+
104+ @app .get ("/invite/{uid_da_agenda}" , responses = STANDARD_RESPONSES )
105+ def mandar_um_convite_para_entrar_na_turma_tipo_o_whatsapp (uid_da_agenda : str , request : Request ):
106+ agenda_node = agenda_ref .child (uid_da_agenda )
107+ agenda_data = agenda_node .get ()
108+
109+ if not agenda_data :
110+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
74111
75- @app .get ("/getAllUsers/" , tags = ["Usuários" ])
112+ # Detecta o dispositivo
113+ user_agent = request .headers .get ("user-agent" , "" ).lower ()
114+
115+ # Deep link do seu app (Expo deve estar configurado com "scheme": "cosmos")
116+ deep_link_url = "cosmos://home"
117+
118+ # URL da Play Store (o pacote deve bater com o app.json do Expo)
119+ play_store_url = "https://play.google.com/store/apps/details?id=com.seuapp.android"
120+
121+ if "android" in user_agent :
122+ intent_url = (
123+ f"intent://home#Intent;"
124+ f"scheme=cosmos;"
125+ f"package=com.seuapp.android;"
126+ f"end"
127+ )
128+ return RedirectResponse (intent_url )
129+
130+ elif "iphone" in user_agent or "ipad" in user_agent :
131+ return RedirectResponse (deep_link_url )
132+
133+ # Fallback para outros dispositivos (desktop, etc)
134+ return RedirectResponse (play_store_url )
135+
136+ @app .get ("/getAllUsers/" , tags = ["Usuários" ], responses = STANDARD_RESPONSES )
76137def conseguir_todos_os_usuarios_logado_com_o_email_normal_no_firebase ():
77138 users = []
78139 page = auth .list_users ()
79140 while page :
80141 for user in page .users :
81142 users .append ({
82143 "uid" : user .uid ,
83- "email" : user .email or "" ,
84- "passwordHash" : user .password_hash or "" ,
85- "passwordSalt" : user .password_salt or "" ,
144+ "email" : user .email ,
145+ "passwordHash" : user .password_hash ,
146+ "passwordSalt" : user .password_salt ,
147+ "display_name" : user .display_name ,
86148 "phone_number" : user .phone_number or "" ,
87- "display_name " : user .display_name or "" ,
149+ "invite_url " : user .invite_url ,
88150 "photo_url" : user .photo_url or "" ,
89151 })
90152 page = page .get_next_page ()
91153 return users
92154
93- @app .post ("/add/user/" , tags = ["Usuários" ])
155+ @app .post ("/add/user/" , tags = ["Usuários" ], responses = STANDARD_RESPONSES )
94156async def criar_um_usuario_com_email_e_senha (email : str , password : str , display_name : str , phone_number : str | None = None , photo_url : str | None = None ):
95157 user = auth .create_user (
96158 email = email ,
@@ -99,97 +161,160 @@ async def criar_um_usuario_com_email_e_senha(email: str, password: str, display_
99161 password = password ,
100162 display_name = display_name ,
101163 photo_url = photo_url ,
164+ invite_url = generate_random_invite_url (),
102165 disabled = False )
103166 message = 'Criado um usuário com sucesso. UID: {0}' .format (user .uid )
104167 return {"message" : message }
105168
106- @app .delete ("/delete/user" , tags = ["Usuários" ])
169+ @app .delete ("/delete/user" , tags = ["Usuários" ], responses = STANDARD_RESPONSES )
107170async def deletar_um_usuario_com_o_uid (uid : str ):
108- auth .delete_user (uid )
109- message = f'O usuário com o UID { uid } foi deletado com sucesso.'
110- return {"message" : message }
171+ if check_uid_exists (uid ):
172+ auth .delete_user (uid )
173+ message = f'O usuário com o UID { uid } foi deletado com sucesso.'
174+ return {"message" : message }
175+ else :
176+ raise HTTPException (status_code = 400 , detail = "Este usuário não existe no banco de dados" )
111177
112- @app .get ("/getAllAgendas" , tags = ["Agenda" ])
178+ @app .get ("/getAllAgendas" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
113179async def mostrar_todas_as_agendas_criadas ():
114180 if agenda_ref .get () is None :
115181 message = f'Nenhuma agenda foi criada'
116182 return {"message" : message }
117183 else :
118184 return agenda_ref .get ()
119185
120- @app .post ("/add/agenda/" , tags = ["Agenda" ])
121- async def criar_uma_agenda (nome_agenda : str ):
122- uid = str (uuid .uuid4 ())
123- agenda_ref .update ({
124- uid : {
125- 'nome_agenda' : nome_agenda
186+ @app .post ("/add/agenda/" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
187+ async def criar_uma_agenda (nome_agenda : str , uid_do_responsavel : str ):
188+ if check_uid_exists (uid_do_responsavel ):
189+ uid = str (uuid .uuid4 ())
190+ agenda_ref .update ({
191+ uid : {
192+ 'nome_agenda' : nome_agenda ,
193+ 'uid_do_responsável' : uid_do_responsavel
194+ }
195+ })
196+ message = f'A agenda { nome_agenda } com o UID { uid } foi criada com sucesso'
197+ return {"message" : message }
198+ else :
199+ raise HTTPException (status_code = 401 , detail = "Este usuário não existe no banco de dados" )
200+
201+ @app .post ("/add/agenda/membro" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
202+ async def adicionar_um_membro_na_agenda_já_criada (uid_da_agenda : str , uid_do_membro : str ):
203+ agenda_node = agenda_ref .child (uid_da_agenda )
204+ agenda_data = agenda_node .get ()
205+ if not agenda_data :
206+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
207+
208+ if not check_uid_exists (uid_do_membro ):
209+ raise HTTPException (status_code = 400 , detail = "Este usuário não existe no banco de dados" )
210+
211+ user = auth .get_user (uid_do_membro )
212+
213+ membro_ref = agenda_node .child ("membros" )
214+ membro_ref .update ({
215+ user .uid : {
216+ 'nome_do_usuário' : user .display_name
126217 }
127218 })
128- message = f'A agenda { nome_agenda } com o UID { uid } foi criada com sucesso'
219+ message = f'O membro { user . display } com o UID { user . uid } foi adicionado com sucesso'
129220 return {"message" : message }
130221
131- @app .post ("/add/agenda/materia" , tags = ["Agenda" ])
132- async def criar_uma_materia_na_agenda (uid_da_agenda : str , matéria : str ):
133- matéria_criada = agenda_ref .child (uid_da_agenda ).child ("matérias" )
222+ @app .post ("/add/agenda/materia" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
223+ async def criar_uma_materia_na_agenda_já_criada (uid_da_agenda : str , nome_da_matéria : str , nome_do_professor : str | None = None , horario_de_inicio_da_materia : str | None = None , horario_de_fim_da_materia : str | None = None ):
224+ agenda_node = agenda_ref .child (uid_da_agenda )
225+ agenda_data = agenda_node .get ()
226+ if not agenda_data :
227+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
228+
229+ matérias_ref = agenda_node .child ("matérias" )
134230 uid = str (uuid .uuid4 ())
135- matéria_criada .update ({
231+ matérias_ref .update ({
136232 uid : {
137- 'nome_matéria' : matéria
233+ 'nome_matéria' : nome_da_matéria ,
234+ 'professor' : nome_do_professor ,
235+ 'horario_de_início' : horario_de_inicio_da_materia ,
236+ "horário_de_fim" : horario_de_fim_da_materia
138237 }
139238 })
140- message = f'A matéria { matéria } com o UID { uid } foi criada com sucesso'
239+ message = f'A matéria { nome_da_matéria } com o UID { uid } foi criada com sucesso'
141240 return {"message" : message }
142241
143- @app .post ("/add/agenda/tarefa" , tags = ["Agenda" ])
144- async def criar_uma_tarefa_na_agenda_criada (uid_da_agenda : str , nome_da_tarefa : str , timestamp : str ):
145- uid = str (uuid .uuid4 ())
146- tarefa_criada = agenda_ref .child (uid_da_agenda ).child ("tarefas" )
242+ @app .post ("/add/agenda/tarefa" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
243+ async def criar_uma_tarefa_na_agenda_já_criada (uid_da_agenda : str , nome_da_tarefa : str , timestamp : str ):
244+ agenda_node = agenda_ref .child (uid_da_agenda )
245+ agenda_data = agenda_node .get ()
246+ if not agenda_data :
247+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
147248
249+ uid = str (uuid .uuid4 ())
250+ tarefa_criada = agenda_node .child ("tarefas" )
148251 tarefa_criada .update ({
149252 uid : {
150253 'nome_da_tarefa' : nome_da_tarefa ,
151254 'timestamp' : timestamp_formatado (timestamp )
152255 }
153256 })
154-
155- message = f'O tarefa com o UID { uid } foi criada com sucesso.'
257+ message = f'A tarefa com o UID { uid } foi criada com sucesso.'
156258 return {"message" : message }
157259
158- @app .post ("/add/agenda/evento" , tags = ["Agenda" ])
159- async def criar_um_evento_na_agenda_criada (uid_da_agenda : str , nome_do_evento : str , timestamp : str ):
160- uid = str (uuid .uuid4 ())
161- evento_criado = agenda_ref .child (uid_da_agenda ).child ("evento" )
260+ @app .post ("/add/agenda/evento" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
261+ async def criar_um_evento_na_agenda_já_criada (uid_da_agenda : str , nome_do_evento : str , timestamp : str ):
262+ agenda_node = agenda_ref .child (uid_da_agenda )
263+ agenda_data = agenda_node .get ()
264+ if not agenda_data :
265+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
162266
267+ uid = str (uuid .uuid4 ())
268+ evento_criado = agenda_node .child ("eventos" )
163269 evento_criado .update ({
164270 uid : {
165271 'nome_do_evento' : nome_do_evento ,
166272 'timestamp' : timestamp_formatado (timestamp )
167273 }
168274 })
169-
170- message = f'O tarefa com o UID { uid } foi criada com sucesso.'
275+ message = f'O evento com o UID { uid } foi criado com sucesso.'
171276 return {"message" : message }
172277
173- @app .delete ("/delete/agenda/" , tags = ["Agenda" ])
174- async def deletar_uma_agenda_com_o_uid (uid : str ):
175- agenda_ref .child (uid ).delete ()
176- message = f'O agenda com o UID { uid } foi deletada com sucesso.'
278+ @app .delete ("/delete/agenda/" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
279+ async def deletar_uma_agenda_com_o_uid (uid_da_agenda : str ):
280+ agenda_node = agenda_ref .child (uid_da_agenda )
281+ agenda_data = agenda_node .get ()
282+ if not agenda_data :
283+ raise HTTPException (status_code = 404 , detail = f"A agenda com o UID { uid_da_agenda } não existe" )
284+
285+ agenda_node .delete ()
286+ message = f'A agenda com o UID { uid_da_agenda } foi deletada com sucesso.'
177287 return {"message" : message }
178288
179- @app .delete ("/delete/agenda/materia" , tags = ["Agenda" ])
289+ @app .delete ("/delete/agenda/materia" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
180290async def deletar_uma_materia_com_o_uid (uid_da_agenda : str , uid_da_materia : str ):
181- agenda_ref .child (uid_da_agenda ).child ("matérias" ).child (uid_da_materia ).delete ()
291+ matéria_node = agenda_ref .child (uid_da_agenda ).child ("matérias" ).child (uid_da_materia )
292+ matéria_data = matéria_node .get ()
293+ if not matéria_data :
294+ raise HTTPException (status_code = 404 , detail = f"A matéria com o UID { uid_da_materia } na agenda { uid_da_agenda } não existe" )
295+
296+ matéria_node .delete ()
182297 message = f'A matéria com o UID { uid_da_materia } foi deletada com sucesso.'
183298 return {"message" : message }
184299
185- @app .delete ("/delete/agenda/tarefa" , tags = ["Agenda" ])
300+ @app .delete ("/delete/agenda/tarefa" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
186301async def deletar_uma_tarefa_com_o_uid (uid_da_agenda : str , uid_da_tarefa : str ):
187- agenda_ref .child (uid_da_agenda ).child ("tarefas" ).child (uid_da_tarefa ).delete ()
302+ tarefa_node = agenda_ref .child (uid_da_agenda ).child ("tarefas" ).child (uid_da_tarefa )
303+ tarefa_data = tarefa_node .get ()
304+ if not tarefa_data :
305+ raise HTTPException (status_code = 404 , detail = f"A tarefa com o UID { uid_da_tarefa } na agenda { uid_da_agenda } não existe" )
306+
307+ tarefa_node .delete ()
188308 message = f'A tarefa com o UID { uid_da_tarefa } foi deletada com sucesso.'
189309 return {"message" : message }
190310
191- @app .delete ("/delete/agenda/evento" , tags = ["Agenda" ])
311+ @app .delete ("/delete/agenda/evento" , tags = ["Agenda" ], responses = STANDARD_RESPONSES )
192312async def deletar_um_evento_com_o_uid (uid_da_agenda : str , uid_do_evento : str ):
193- agenda_ref .child (uid_da_agenda ).child ("evento" ).child (uid_do_evento ).delete ()
313+ evento_node = agenda_ref .child (uid_da_agenda ).child ("eventos" ).child (uid_do_evento )
314+ evento_data = evento_node .get ()
315+ if not evento_data :
316+ raise HTTPException (status_code = 404 , detail = f"O evento com o UID { uid_do_evento } na agenda { uid_da_agenda } não existe" )
317+
318+ evento_node .delete ()
194319 message = f'O evento com o UID { uid_do_evento } foi deletado com sucesso.'
195320 return {"message" : message }
0 commit comments