AIdeaText commited on
Commit
6cddee1
verified
1 Parent(s): b67a453

Update modules/database/sql_db.py

Browse files
Files changed (1) hide show
  1. modules/database/sql_db.py +289 -24
modules/database/sql_db.py CHANGED
@@ -1,42 +1,307 @@
1
- # modules/database/sql_db.py
2
 
3
- from modules.database.database_init import get_database_client
 
4
  import logging
 
 
5
 
6
  logger = logging.getLogger(__name__)
7
 
8
- # Nombre de la base de datos y contenedor
9
- DATABASE_NAME = "user_database"
10
- USER_CONTAINER_NAME = "users"
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- def get_user_container():
13
- """Obtiene el contenedor de usuarios."""
14
- db_client = get_database_client(DATABASE_NAME)
15
- return db_client.get_container_client(USER_CONTAINER_NAME)
16
 
17
- def create_user(username, password, role):
18
- """Crea un nuevo usuario."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  try:
20
- container = get_user_container()
 
 
 
21
  user_data = {
22
- "id": username,
23
- "password": password,
24
- "role": role
 
 
 
 
 
25
  }
 
26
  container.create_item(body=user_data)
27
- logger.info(f"Usuario creado: {username}")
28
  return True
 
29
  except Exception as e:
30
- logger.error(f"Error creando usuario: {e}")
31
  return False
32
 
33
- def get_user(username):
34
- """Obtiene un usuario por su username."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  try:
36
- container = get_user_container()
37
- query = f"SELECT * FROM c WHERE c.id = '{username}'"
38
- items = list(container.query_items(query=query, enable_cross_partition_query=True))
39
- return items[0] if items else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  except Exception as e:
41
- logger.error(f"Error obteniendo usuario: {e}")
42
  return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #modules/database/sql_db.py
2
 
3
+ from .database_init import get_container
4
+ from datetime import datetime, timezone
5
  import logging
6
+ import bcrypt
7
+ import uuid
8
 
9
  logger = logging.getLogger(__name__)
10
 
11
+ def get_user(username, role=None):
12
+ container = get_container("users")
13
+ try:
14
+ query = f"SELECT * FROM c WHERE c.id = '{username}'"
15
+ if role:
16
+ query += f" AND c.role = '{role}'"
17
+ items = list(container.query_items(
18
+ query=query,
19
+ enable_cross_partition_query=True
20
+ ))
21
+ return items[0] if items else None
22
+ except Exception as e:
23
+ logger.error(f"Error al obtener usuario {username}: {str(e)}")
24
+ return None
25
 
26
+ def get_admin_user(username):
27
+ return get_user(username, role='Administrador')
 
 
28
 
29
+ def get_student_user(username):
30
+ return get_user(username, role='Estudiante')
31
+
32
+ def get_teacher_user(username):
33
+ return get_user(username, role='Profesor')
34
+
35
+ #################################################################################
36
+ #El error ocurre porque el par谩metro `partition_key`
37
+ #no es soportado en la versi贸n actual del SDK.
38
+ #Modifiquemos la funci贸n `create_user()` para incluir la partici贸n en el cuerpo del documento:
39
+
40
+ def create_user(username, password, role, additional_info=None):
41
+ container = get_container("users")
42
+ if not container:
43
+ logger.error("No se pudo obtener el contenedor de usuarios")
44
+ return False
45
+
46
  try:
47
+ # Generar salt y hash de la contrase帽a
48
+ salt = bcrypt.gensalt()
49
+ hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
50
+
51
  user_data = {
52
+ 'id': username,
53
+ 'password': hashed.decode('utf-8'),
54
+ 'salt': salt.decode('utf-8'),
55
+ 'role': role,
56
+ 'timestamp': datetime.now(timezone.utc).isoformat(),
57
+ 'additional_info': additional_info or {},
58
+ # La partici贸n va dentro del documento
59
+ 'partitionKey': username
60
  }
61
+
62
  container.create_item(body=user_data)
63
+ logger.info(f"Usuario {role} creado: {username}")
64
  return True
65
+
66
  except Exception as e:
67
+ logger.error(f"Error al crear usuario {role}: {str(e)}")
68
  return False
69
 
70
+ #########################################################################
71
+ def create_student_user(username, password, additional_info=None):
72
+ return create_user(username, password, 'Estudiante', additional_info)
73
+
74
+ def create_teacher_user(username, password, additional_info=None):
75
+ return create_user(username, password, 'Profesor', additional_info)
76
+
77
+ def create_admin_user(username, password, additional_info=None):
78
+ return create_user(username, password, 'Administrador', additional_info)
79
+
80
+ ############-- Funciones de control del tiempo de sesi贸n ##################
81
+
82
+ ###########################################################
83
+
84
+ def record_login(username):
85
+ """Registra el inicio de sesi贸n de un usuario"""
86
  try:
87
+ container = get_container("users_sessions")
88
+ if not container:
89
+ logger.error("No se pudo obtener el contenedor users_sessions")
90
+ return None
91
+
92
+ session_id = str(uuid.uuid4())
93
+ session_doc = {
94
+ "id": session_id,
95
+ "type": "session",
96
+ "username": username,
97
+ "loginTime": datetime.now(timezone.utc).isoformat(),
98
+ "additional_info": {},
99
+ # El campo para partition key debe estar en el documento
100
+ "partitionKey": username
101
+ }
102
+
103
+ # Crear el documento usando options
104
+ result = container.create_item(
105
+ body=session_doc,
106
+ enable_cross_partition_query=True
107
+ )
108
+ logger.info(f"Sesi贸n {session_id} registrada para {username}")
109
+ return session_id
110
  except Exception as e:
111
+ logger.error(f"Error registrando login: {str(e)}")
112
  return None
113
+
114
+
115
+ ###########################################################
116
+
117
+ def record_logout(username, session_id):
118
+ """Registra el cierre de sesi贸n y calcula la duraci贸n"""
119
+ try:
120
+ container = get_container("users_sessions")
121
+ if not container:
122
+ logger.error("No se pudo obtener el contenedor users_sessions")
123
+ return False
124
+
125
+ # Obtener la sesi贸n actual
126
+ query = "SELECT * FROM c WHERE c.id = @id AND c.username = @username"
127
+ params = [
128
+ {"name": "@id", "value": session_id},
129
+ {"name": "@username", "value": username}
130
+ ]
131
+
132
+ items = list(container.query_items(
133
+ query=query,
134
+ parameters=params,
135
+ enable_cross_partition_query=True
136
+ ))
137
+
138
+ if not items:
139
+ logger.warning(f"Sesi贸n no encontrada: {session_id}")
140
+ return False
141
+
142
+ session = items[0]
143
+ login_time = datetime.fromisoformat(session['loginTime'].rstrip('Z'))
144
+ logout_time = datetime.now(timezone.utc)
145
+ duration = int((logout_time - login_time).total_seconds())
146
+
147
+ session.update({
148
+ "logoutTime": logout_time.isoformat(),
149
+ "sessionDuration": duration
150
+ })
151
+
152
+ # Actualizar el documento
153
+ container.upsert_item(
154
+ body=session
155
+ )
156
+ logger.info(f"Sesi贸n {session_id} cerrada para {username}, duraci贸n: {duration}s")
157
+ return True
158
+ except Exception as e:
159
+ logger.error(f"Error registrando logout: {str(e)}")
160
+ return False
161
+
162
+
163
+ ###########################################################
164
+
165
+ def get_recent_sessions(limit=10):
166
+ """Obtiene las sesiones m谩s recientes"""
167
+ try:
168
+ container = get_container("users_sessions")
169
+ if not container:
170
+ logger.error("No se pudo obtener el contenedor users_sessions")
171
+ return []
172
+
173
+ query = """
174
+ SELECT c.username, c.loginTime, c.logoutTime, c.sessionDuration
175
+ FROM c
176
+ WHERE c.type = 'session'
177
+ ORDER BY c.loginTime DESC
178
+ OFFSET 0 LIMIT @limit
179
+ """
180
+
181
+ sessions = list(container.query_items(
182
+ query=query,
183
+ parameters=[{"name": "@limit", "value": limit}],
184
+ enable_cross_partition_query=True
185
+ ))
186
+
187
+ # Validar y limpiar los datos
188
+ clean_sessions = []
189
+ for session in sessions:
190
+ try:
191
+ clean_sessions.append({
192
+ "username": session["username"],
193
+ "loginTime": session["loginTime"],
194
+ "logoutTime": session.get("logoutTime", "Activo"),
195
+ "sessionDuration": session.get("sessionDuration", 0)
196
+ })
197
+ except KeyError as e:
198
+ logger.warning(f"Sesi贸n con datos incompletos: {e}")
199
+ continue
200
+
201
+ return clean_sessions
202
+ except Exception as e:
203
+ logger.error(f"Error obteniendo sesiones recientes: {str(e)}")
204
+ return []
205
+
206
+
207
+
208
+ ###########################################################
209
+
210
+ def get_user_total_time(username):
211
+ """Obtiene el tiempo total que un usuario ha pasado en la plataforma"""
212
+ try:
213
+ container = get_container("users_sessions")
214
+ if not container:
215
+ return None
216
+
217
+ query = """
218
+ SELECT VALUE SUM(c.sessionDuration)
219
+ FROM c
220
+ WHERE c.type = 'session'
221
+ AND c.username = @username
222
+ AND IS_DEFINED(c.sessionDuration)
223
+ """
224
+
225
+ result = list(container.query_items(
226
+ query=query,
227
+ parameters=[{"name": "@username", "value": username}],
228
+ enable_cross_partition_query=True
229
+ ))
230
+
231
+ return result[0] if result and result[0] is not None else 0
232
+ except Exception as e:
233
+ logger.error(f"Error obteniendo tiempo total: {str(e)}")
234
+ return 0
235
+
236
+ ###########################################################
237
+ def update_student_user(username, new_info):
238
+ user_container, _, _ = get_sql_containers()
239
+ try:
240
+ user = get_student_user(username)
241
+ if user:
242
+ user['additional_info'].update(new_info)
243
+ user_container.upsert_item(body=user)
244
+ logger.info(f"Informaci贸n del estudiante actualizada: {username}")
245
+ return True
246
+ else:
247
+ logger.warning(f"Intento de actualizar estudiante no existente: {username}")
248
+ return False
249
+ except Exception as e:
250
+ logger.error(f"Error al actualizar informaci贸n del estudiante {username}: {str(e)}")
251
+ return False
252
+
253
+
254
+ def delete_student_user(username):
255
+ user_container, _, _ = get_sql_containers()
256
+ try:
257
+ user = get_student_user(username)
258
+ if user:
259
+ user_container.delete_item(item=user['id'], partition_key=username)
260
+ logger.info(f"Estudiante eliminado: {username}")
261
+ return True
262
+ else:
263
+ logger.warning(f"Intento de eliminar estudiante no existente: {username}")
264
+ return False
265
+ except Exception as e:
266
+ logger.error(f"Error al eliminar estudiante {username}: {str(e)}")
267
+ return False
268
+
269
+ def store_application_request(name, lastname, email, institution, current_role, desired_role, reason):
270
+ _, application_requests_container, _ = get_sql_containers()
271
+ try:
272
+ application_request = {
273
+ "id": str(uuid.uuid4()),
274
+ "name": name,
275
+ "lastname": lastname,
276
+ "email": email,
277
+ "institution": institution,
278
+ "current_role": current_role,
279
+ "desired_role": desired_role,
280
+ "reason": reason,
281
+ "requestDate": datetime.utcnow().isoformat()
282
+ }
283
+ application_requests_container.create_item(body=application_request)
284
+ logger.info(f"Solicitud de aplicaci贸n almacenada para el email: {email}")
285
+ return True
286
+ except Exception as e:
287
+ logger.error(f"Error al almacenar la solicitud de aplicaci贸n: {str(e)}")
288
+ return False
289
+
290
+ def store_student_feedback(username, name, email, feedback):
291
+ _, _, user_feedback_container = get_sql_containers()
292
+ try:
293
+ feedback_item = {
294
+ "id": str(uuid.uuid4()),
295
+ "username": username,
296
+ "name": name,
297
+ "email": email,
298
+ "feedback": feedback,
299
+ "role": "Estudiante",
300
+ 'timestamp': datetime.now(timezone.utc).isoformat(),
301
+ }
302
+ result = user_feedback_container.create_item(body=feedback_item)
303
+ logger.info(f"Feedback de estudiante almacenado con ID: {result['id']} para el usuario: {username}")
304
+ return True
305
+ except Exception as e:
306
+ logger.error(f"Error al almacenar el feedback del estudiante {username}: {str(e)}")
307
+ return False