
    Yeha                     @   d dl mZmZmZmZmZmZmZ d dlm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlZd dlZd dlZd dlZd dlZ ed	
          Z ej        e                                          j        Z e dz  Z!e"                    ed            edgd          Z#e$                    d ed          d            ed          Z%d Z&d Z'de(fdZ)de*fdZ+e,                    dd           ed           ed          fded e(d!e-dz  fd"            Z.d#e-fd$Z/d e(fd%Z0dd'e-d#e-d(e-d)e-fd*Z1d dl2Z2d dl3Z3d dl4Z4d dl5Z6d dlZ7d+ Z8dd-e(de-fd.Z9defd/Z:d0 Z;d e(fd1Z<d2e(fd3Z=d2e(d4e(fd5Z>d d6l mZ e,                    d7d8           ed           ed           ed          fded9e(d!e-dz  d:e(dz  fd;            Z?e@                    d<e	=          defd>            ZAe@                    d?e	=          defd@            ZBe@                    dAe	=          defdB            ZCe@                    dCe	=          defdD            ZDe@                    dEdFe	G          defdH            ZEe,                    dEdIe	G           ed           ed          fded#e-d(e-fdJ            ZFe@                    dKdLe	G          defdM            ZGe@                    dNedOP          d e(defdQ            ZHe@                    dRdSe	G          defdT            ZIe,                    dRdUe	G           ed           ed           ed          fded'e-d#e-d(e-fdV            ZJd dWl mZ d dXlm	Z	 e@                    dYdZe	G          defd[            ZKe dz  d\z  d]z  ZLe,                    dYd^          defd_            ZMe@                    d`dae	G          dded#e-dz  fdb            ZNe,                    d`dce	G           ed           ed           ed           ed          fded#e-dde-d'e-dz  d(e-dz  f
de            ZOe@                    dfe	=          defdg            ZPe@                    dhdie	G          defdj            ZQe@                    dke	=          defdl            ZRe@                    dm          defdn            ZSd dl mZmZmZmZmZmZmZ d dlm	Z	m
Z
mZ e@                    dodpe	G          dded e(dz  fdq            ZTd drl5mUZU e,                    dods           ed           ed           ed           ed           ed          fded4e(dte-due-d!e-dz  dve(dz  fdw            ZVe@                    dxedyP          defdz            ZWh d{ZX G d| d}e          ZYd e(d)e-fd~ZZe@                    dedP          defd            Z[e,                    dd          d e(deYdefd            Z\d dl]m^Z^m_Z_m`Z`maZa d dlmZ d dlmZ d dlmZmbZbmcZc d dlZ7d dl mdZd eae- ecd          f         Zeeae- ecd          f         Zf G d de          Zg G d de          Zhd dl mdZd d dl]m^Z^m_Z_m`Z`miZi d dlmjZk d dlZ7e@                    d           edddd           edddd          dddddfde^e(         de^e(         de^e-         de^e-         de-de-de(fd            Zld dlmZmmZm de-dene(e(f         fdZode-de(fdZpde(de(de(de(de*f
dZqddZrd dWl mZ d dlZdefdZsdejt        de_e-e`f         fdZue,                    dev          dedegfd            Zwex                    dev          dede(dehfd            Zyez                    dev          dede(fd            Z{d dl]m^Z^miZi e@                    deiev                   	 	 	 	 ddede^e-         de^e-         d e^e(         de^e-         f
d            Z|e@                    dedP          defd            Z}e@                    de	=          defd            Z~e@                    de	=          defdĄ            Ze,                    de	=           ed           ed           ed           ed           ed           ed           ed           ed          fded'e-d#e-de-dede-de-de-de-fd˄            Ze@                    de	=          defd̈́            Zd dlZd dlZ	 d dlmZ dZn# e$ r dZY nw xY wde-de-fd҄Zde-de-de*fdԄZd d6l mZ e,                    de	=           ed           ed           ed          fdede-de-de-fdل            Ze@                    dڦ          defdۄ            Ze@                    dܦ          d݄             Ze                    dަ          d߄             ZdS )    )FastAPIRequestForm
UploadFileFileBodyHTTPException)HTMLResponseRedirectResponseJSONResponse)StaticFiles)Jinja2Templates)SessionMiddleware)CryptContext)	BaseModelN	TheL4FPRO)titlez
db.sqlite3none)
secret_keybcryptauto)schemes
deprecatedz/staticz
app/static)	directorystatic)namezapp/templatesc                     t          j        t                    5 } |                     d           |                     d           	 |                     d           n# t           j        $ r Y nw xY w	 |                     d           n# t           j        $ r Y nw xY w|                     d          }d |                                D             }d|vr*|                     d           |                     d	           |                     d          }d
 |                                D             }d|vr|                     d           d|vr|                     d           |                     d          }d |                                D             }d|vr|                     d           d|vr|                     d           d|vr|                     d           d|vr|                     d           d } || dd            || dd            || dd            || dd            || dd            || dd            || d d            || d!d            || d"d            || d#d            || d$d            || d%d            || d&d            || d'd            || d(d            || d)d            || d*d            || d+d           	 |                     d,           n# t           j        $ r Y nw xY w|                     d-           |                     d.           |                     d/           |                     d0           |                     d1           |                     d2           |                     d3           |                     d4           |                                  d d d            d S # 1 swxY w Y   d S )5Na"  
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT NOT NULL UNIQUE,
                password_hash TEXT NOT NULL,
                created_at TEXT NOT NULL
            )
        a   
            CREATE TABLE IF NOT EXISTS reservations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                created_at TEXT NOT NULL,
                date TEXT NOT NULL,
                time TEXT NOT NULL,
                duration_minutes INTEGER NOT NULL,
                price_cents INTEGER NOT NULL,
                name TEXT,
                email TEXT,
                phone TEXT,
                notes TEXT,
                user_id INTEGER,
                status TEXT NOT NULL DEFAULT 'confirmada'
            )
        zQALTER TABLE notifications ADD COLUMN deleted_by_sender INTEGER NOT NULL DEFAULT 0zTALTER TABLE notifications ADD COLUMN deleted_by_recipient INTEGER NOT NULL DEFAULT 0PRAGMA table_info(users)c                     h | ]
}|d          S     .0rows     %/var/www/tusenda/the4fpro/app/main.py	<setcomp>zinit_db.<locals>.<setcomp>F       1113A111    rolez@ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'alumno'z@UPDATE users SET role = 'alumno' WHERE role IS NULL OR role = ''c                     h | ]
}|d          S r    r"   r#   s     r&   r'   zinit_db.<locals>.<setcomp>M   r(   r)   phonez'ALTER TABLE users ADD COLUMN phone TEXTavatarz(ALTER TABLE users ADD COLUMN avatar TEXTc                     h | ]
}|d          S r    r"   r#   s     r&   r'   zinit_db.<locals>.<setcomp>U   r(   r)   teamz&ALTER TABLE users ADD COLUMN team TEXTcategoryz*ALTER TABLE users ADD COLUMN category TEXTpositionz*ALTER TABLE users ADD COLUMN position TEXTinjury_historyz0ALTER TABLE users ADD COLUMN injury_history TEXTc                     |                      d          }d |                                D             }||vr|                      d| d|            d S d S )Nr   c                     h | ]
}|d          S r    r"   r#   s     r&   r'   z3init_db.<locals>.add_user_column.<locals>.<setcomp>b   s    9993A999r)   zALTER TABLE users ADD COLUMN  )executefetchall)connr   ddlcurexistings        r&   add_user_columnz init_db.<locals>.add_user_column`   sk    ,,9::C99#,,..999H8##ITIICIIJJJJJ $#r)   dniTEXT
birth_datecitydominant_foot	strengths
weaknessestraining_typephysical_workphysical_work_detailssmokingalcoholrecovery
chest_pain
discomfortwhatsapp_contentvideo_permissionprivacy_acceptancedata_confirmationz@ALTER TABLE notifications ADD COLUMN reservation_id INTEGER NULLzYCREATE INDEX IF NOT EXISTS idx_notifications_reservation ON notifications(reservation_id)a  
            CREATE TABLE IF NOT EXISTS "formulario-registro" (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                created_at TEXT NOT NULL,
                expires_at TEXT NOT NULL,
                email TEXT NOT NULL,
                pin TEXT NOT NULL,
                data_json TEXT NOT NULL,
                used INTEGER NOT NULL DEFAULT 0,
                used_at TEXT
            )
        zMCREATE INDEX IF NOT EXISTS idx_form_reg_email ON "formulario-registro"(email)zICREATE INDEX IF NOT EXISTS idx_form_reg_pin ON "formulario-registro"(pin)zTCREATE INDEX IF NOT EXISTS idx_form_reg_expires ON "formulario-registro"(expires_at)aC  
            CREATE TABLE IF NOT EXISTS academy_registrations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                data_json TEXT NOT NULL,
                created_at TEXT NOT NULL,
                FOREIGN KEY(user_id) REFERENCES users(id)
            )
        zOCREATE INDEX IF NOT EXISTS idx_acad_regs_user ON academy_registrations(user_id)zUCREATE INDEX IF NOT EXISTS idx_acad_regs_created ON academy_registrations(created_at))sqlite3connectDB_PATHr6   OperationalErrorr7   commit)r8   r:   colsr<   s       r&   init_dbrV      s/   		!	! HT  	 	 	 	  	 	 	"	LLlmmmm' 	 	 	D		LLopppp' 	 	 	D	 ll56611#,,..111LL[\\\LL[\\\ ll56611#,,..111$LLBCCC4LLCDDD ll56611#,,..111LLABBBT!!LLEFFFT!!LLEFFF4''LLKLLL	K 	K 	K 	eV,,,lF333ff--- 	ov666k6222lF333ov666 	ov6665v>>>i000i000j&111lF333lF333 	0&9990&9992F;;;16:::	LL[\\\\' 	 	 	D	pqqq 	  	 	 	 	deee`aaaklll 	  	 	 	 	fggglmmmQH H H H H H H H H H H H H H H H H Hs   +OAOA.+O-A..O2BOBOBIO(K>=O>LOLB?OO #O c                      t          j        t                    } t           j        | _        |                     d           | S )NzPRAGMA foreign_keys = ON;)rP   rQ   rR   Rowrow_factoryr6   r8   s    r&   _connr[      s3    ?7##D{DLL,---Kr)   returnc                      t                      5 } |                     d                                          }t          |d         pd          cd d d            S # 1 swxY w Y   d S )Nz2SELECT COUNT(1) AS c FROM users WHERE role='admin'cr   )r[   r6   fetchoneint)r8   r%   s     r&   count_adminsra      s    	 "DllOPPYY[[3s8=q!!" " " " " " " " " " " " " " " " " "s   >AA!Ac                 4    t          | d                   dk    S )Nr*   admin)str)mes    r&   is_adminrf      s    r&z??g%%r)   z/admin/users/deleteadmin_delete_user.requestuser_idnext_urlc                   K   t          |           }|st          dd          S t          |          st          dd          t	          |          }|st          dd          t          |d	                   t          |d	                   k    rt          d
d          t          |d                   dk    r#t                      dk    rt          d
d          t                      5 }	 |	                    d           |	                    d||f           |	                    d|f           |	                    d|f           |	                    d|f           |
                                 n## t          $ r |                                  w xY w	 d d d            n# 1 swxY w Y   |r8ddlm}  ||          }|j        dk    r|j        dk    rt          |d          S t          dd          S )N/login/  urlstatus_code  z&Solo un admin puede eliminar usuarios.rp   detail  zUsuario no encontrado.id  z$No puedes eliminar tu propia cuenta.r*   rc   r!   u$   No puedes eliminar al último admin.BEGINzADELETE FROM notifications WHERE sender_id = ? OR recipient_id = ?z+DELETE FROM reservations  WHERE user_id = ?z3DELETE FROM academy_registrations WHERE user_id = ?zDELETE FROM users WHERE id = ?r   urlparse /admin)current_userr   rf   r	   get_user_by_idr`   rd   ra   r[   r6   rT   	Exceptionrollbackurllib.parsery   schemenetloc)rh   ri   rj   re   targetr8   ry   ps           r&   rg   rg      sm      
g		B ?H#>>>>B<< ^4\]]]]G$$F N4LMMMM 2d8}}F4L))))4Z[[[[ 6&>g%%,..A*=*=4Z[[[[ 
 D	LL!!!LL\_fho^pqqqLLF
SSSLLNQXPZ[[[LL9G:FFFKKMMMM 	 	 	MMOOO	                  C))))))HX8r>>ah"nn#cBBBBc::::s+   .F'0BE76F'7 FF''F+.F+emailc                     t          j        t                    5 }t           j        |_        |                    d| f          }|                                cd d d            S # 1 swxY w Y   d S )Nz#SELECT * FROM users WHERE email = ?rP   rQ   rR   rX   rY   r6   r_   )r   r8   r:   s      r&   get_user_by_emailr      s    		!	! T";ll@5(KK||~~                    <A##A'*A'c                     t          j        t                    5 }t           j        |_        |                    d| f          }|                                cd d d            S # 1 swxY w Y   d S )Nz SELECT * FROM users WHERE id = ?r   ri   r8   r:   s      r&   r}   r}      s    		!	! T";ll=zJJ||~~                 r   alumnor   passwordr*   c           	      X   t                               |          }t          j        t                    5 }|                    d| ||t          j                                        	                                |f           |
                                 d d d            d S # 1 swxY w Y   d S )NzSINSERT INTO users (name, email, password_hash, created_at, role) VALUES (?,?,?,?,?))pwd_contexthashrP   rQ   rR   r6   dtdatetimeutcnow	isoformatrT   )r   r   r   r*   password_hashr8   s         r&   create_userr      s    $$X..M		!	! Ta5-););)=)=)G)G)I)I4P	
 	
 	
 	                 s   ABB#&B#c                     t                      5 } |                     dt          j                                                                        f           |                                  d d d            d S # 1 swxY w Y   d S )NzADELETE FROM "formulario-registro" WHERE used=0 AND expires_at < ?)r[   r6   r   r   r   r   rT   rZ   s    r&   purge_expired_temp_regsr   	  s    	 DX[][f[m[m[o[o[y[y[{[{Z}~~~                 s   AA66A:=A:   lengthc                    t           j        	 d                    fdt          |           D                       }t	                      5 }|                    d|t          j                                        	                                f          
                                }|s|cd d d            S 	 d d d            n# 1 swxY w Y   )NTrz   c              3   @   K   | ]}t          j                  V  d S N)secretschoice)r$   _digitss     r&   	<genexpr>z&generate_unique_pin.<locals>.<genexpr>  s-      DDgnV,,DDDDDDr)   zQSELECT 1 FROM "formulario-registro" WHERE pin = ? AND used = 0 AND expires_at > ?)stringr   joinranger[   r6   r   r   r   r   r_   )r   pinr8   r%   r   s       @r&   generate_unique_pinr     s   ]FggDDDDeFmmDDDDDWW 	,,cbk((**44667  hjj   	 	 	 	 	 	 	 	
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   ACCCc                 v    | j                             d          }|sd S t          t          |                    S )Nri   )sessiongetr}   r`   )rh   ri   s     r&   r|   r|     s8    o!!),,G t#g,,'''r)   c                      t          j        t                    5 } t           j        | _        |                     d          }|                                cd d d            S # 1 swxY w Y   d S )NzCSELECT id, name, email FROM users WHERE role='alumno' ORDER BY namerP   rQ   rR   rX   rY   r6   r7   )r8   r:   s     r&   get_studentsr   "  s    		!	! T";ll`aa||~~                 s   :A!!A%(A%c                     t          j        t                    5 }t           j        |_        |                    d| f          }|                                cd d d            S # 1 swxY w Y   d S )Na  
            SELECT n.id, n.created_at, n.title, n.body,
                   s.name AS sender_name, n.sender_id, n.recipient_id,
                   n.reservation_id
            FROM notifications n
            LEFT JOIN users s ON s.id = n.sender_id
            WHERE n.recipient_id = ?
              AND COALESCE(n.deleted_by_recipient, 0) = 0
            ORDER BY n.created_at DESC
        r   r   s      r&   get_notifications_for_userr   (  s    		!	! T";ll 	 Z	 	 ||~~                 r   	sender_idc                     t          j        t                    5 }t           j        |_        |                    d| f          }|                                cd d d            S # 1 swxY w Y   d S )Na  
            SELECT n.id, n.created_at, n.title, n.body,
                   r.name AS recipient_name, n.sender_id, n.recipient_id,
                   n.reservation_id
            FROM notifications n
            LEFT JOIN users r ON r.id = n.recipient_id
            WHERE n.sender_id = ?
              AND COALESCE(n.deleted_by_sender, 0) = 0
            ORDER BY n.created_at DESC
        r   )r   r8   r:   s      r&   get_notifications_sent_by_userr   8  s    		!	! T";ll 	 \	 	 ||~~                 r   recipient_idc                     t          j        t                    5 }t           j        |_        |                    d| |f          }|                                cddd           S # 1 swxY w Y   dS )u   Enviadas del docente hacia un alumno concreto, ocultando las que ya están borradas
    por cualquiera de las partes cuando se gestiona la bandeja del alumno.a  
            SELECT n.id, n.created_at, n.title, n.body,
                   r.name AS recipient_name, n.sender_id, n.recipient_id,
                   n.reservation_id
            FROM notifications n
            LEFT JOIN users r ON r.id = n.recipient_id
            WHERE n.sender_id = ?
              AND n.recipient_id = ?
              AND COALESCE(n.deleted_by_sender, 0) = 0
              AND COALESCE(n.deleted_by_recipient, 0) = 0
            ORDER BY n.created_at DESC
        Nr   )r   r   r8   r:   s       r&   &get_notifications_sent_by_user_to_userr   I  s     
	!	! T";ll  &( ( ||~~                 s   =A$$A(+A()r   z/notificaciones/eliminardelete_notificationnotification_idtarget_recipient_idc                 L  K   t          |           }|st          dd          S t          j        t                    5 }t          j        |_        |                    d|f                                          }|st          dd          t          |d                   }|d	         t          |d	                   nd }t          |d
                   }	||	k    r,|                    d|f           |                                 n|_||k    rY|+t          |          |	k    r|                    d|f           n|                    d|f           |                                 n\|d         dv rA|?t          |          |	k    r,|                    d|f           |                                 nt          dd          d d d            n# 1 swxY w Y   |r8ddlm}
  |
|          }|j        dk    r|j        dk    rt          |d          S t          dd          S )Nrl   rm   rn   zBSELECT id, sender_id, recipient_id FROM notifications WHERE id = ?rt   u   Notificación no encontrada.rr   ru   r   r   z>UPDATE notifications SET deleted_by_recipient = 1 WHERE id = ?zUUPDATE notifications SET deleted_by_sender = 1, deleted_by_recipient = 1 WHERE id = ?z;UPDATE notifications SET deleted_by_sender = 1 WHERE id = ?r*   docenterc   rq   u&   No puedes eliminar esta notificación.r   rx   rz   /notificaciones)r|   r   rP   rQ   rR   rX   rY   r6   r_   r	   r`   rT   r   ry   r   r   )rh   r   rj   r   re   r8   r%   me_idr   r   ry   r   s               r&   r   r   `  s      
g		B ?H#>>>>		!	! 2bT";llP
 
 (** 	
  	XC8VWWWWBtH-0-=-ICK()))t	3~.// L  LLP "   KKMMMM "u	'9'9 #.37J3K3K|3[3[# %&	    Q$&   KKMMMM Z///4G4S())\99LLP "   KKMMMM  C8`aaaae2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2bj  C))))))HX8r>>ah"nn#cBBBB 1sCCCCs   FGGG/)response_classc                 `   K   t          |           }t                              d| |d          S )Nz
index.htmlrh   userr|   	templatesTemplateResponserh   re   s     r&   homer     2      	g		B%%lQS4T4TUUUr)   z/aboutc                 `   K   t          |           }t                              d| |d          S )Nz
about.htmlr   r   r   s     r&   aboutr     r   r)   z
/membresiac                 \   K   t                               d| t          |           d          S )Nzmembresia.htmlr   r   r   r|   rh   s    r&   	membresiar     s9      %%&6W%%9 9   r)   z
/ticketingc                 \   K   t                               d| t          |           d          S )Nzticketing.htmlr   r   r   s    r&   	ticketingr     s/      %%&6GUabiUjUj8k8klllr)   rl   login)r   r   c                 B   K   t                               d| d d          S )N
login.htmlrh   error)r   r   r   s    r&   	login_getr     s%      %%lRV4W4WXXXr)   
login_postc                 `  K   |                                                                 }t          |          }|r!t                              ||d                   st
                              d| dd          S t          |d                   | j        d<   |d         | j        d<   |d         dk    s|d	k    r$t          | 
                    d          d
          S |d         dk    r$t          | 
                    d          d
          S t          | 
                    d          d
          S )Nr   r   u   Credenciales inválidasr   ru   ri   r*   rc   admin@admin.esrm   rn   r   	dashboard)striplowerr   r   verifyr   r   r`   r   r   url_for)rh   r   r   
email_normr   s        r&   r   r     s)     $$&&JZ((D  
{))(D4IJJ 
))*CDD
 
 	
 "%T$ZGOI"6lGOF F|w*0@"@"@GOOG$<$<#NNNN	f	"	"GOOI$>$>CPPPPGOOK$@$@cRRRRr)   z/docenter   c                 
  K   t          |           }|s$t          |                     d          d          S g }	 |d         dv rt                      }n# t          $ r g }Y nw xY wt
                              d| ||d          S )Nr   rm   rn   r*   r   zdocente.html)rh   r   students)r|   r   r   r   r~   r   r   )rh   re   r   s      r&   docente_dashboardr     s      	g		B OGOOG$<$<#NNNN Hf:---#~~H    %% 	
 	
  s   A A#"A#z/api/users/{user_id}api_user_detail)r   r   c                   K   t          |          }|st          dd          S |d         dvrt          dd          t          j        t
                    5 }t          j        |_        |                    d	| f          	                                }d d d            n# 1 swxY w Y   |st          d
d          t          |          S )Nrl   rm   rn   r*   r   rq   zSolo docentes o adminrr   a  
            SELECT
                id, name, email, created_at, role, phone, avatar, dni, birth_date, city, dominant_foot, team, category, position, injury_history, strengths, weaknesses, training_type, physical_work, physical_work_details, smoking, alcohol, recovery, chest_pain, discomfort, whatsapp_content, video_permission, privacy_acceptance, data_confirmation
            FROM users
            WHERE id = ?
        rt   Usuario no encontrado)r|   r   r	   rP   rQ   rR   rX   rY   r6   r_   dict)ri   rh   re   r8   r%   s        r&   r   r     s     	g		B ?H#>>>> 
&z---4KLLLL		!	! $T";ll 
 Z 
 " 	$ $ $ $ $ $ $ $ $ $ $ $ $ $ $  M4KLLLL99s   ;B  B$'B$z	/registerregisterc                 r   K   t          |           }|pdddd}t                              d| d |d          S )Nrz   r   r   r,   register.htmlrh   r   r   r   )rh   re   ctx_users      r&   register_getr     sI      	g		B;b2;;H%%o7UYck7l7lmmmr)   register_postc           	        K   |                                                                 }t          |          r5t                              d| d|                                 |ddd          S t          |          dk     r5t                              d| d|                                 |ddd          S t          |                                 ||d	           t          |          }t          |d
                   | j        d<   |d         | j        d<   |d         dk    s|dk    r$t          | 
                    d          d          S t          | 
                    d          d          S )Nr   zEse email ya existerz   r   r   r   u'   La contraseña debe tener 6+ caracteresr   r*   ru   ri   r*   rc   r   rm   rn   r   )r   r   r   r   r   lenr   r`   r   r   r   )rh   r   r   r   r   r   s         r&   r   r     s     $$&&J$$ 
))*?RVR\R\R^R^is  A  JB  JB  C  C
 
 	
 8}}q))*Sfjfpfpfrfr  ~H  SU  ^V  ^V  W  W
 
 	
 

j(BBBB Z((D!$T$ZGOI"6lGOF F|w*0@"@"@GOOG$<$<#NNNNGOOK$@$@cRRRRr)   )r	   )r
   z/academy-registeracademy_register_getc                 `   K   t          |           }t                              d| |d          S )Nzacademy-register.htmlr   r   r   s     r&   r   r   9  s9      	g		B%%R((  r)   uploadsacademyacademy_register_postc                   K   |                                   d {V }|                    d          pd                                                                }|st	          dd          t                       t          j                                        }d}|t          j	        |          z   }t          d          }d }|                    d	          }t          |t                    rQ|j        rIt          j                            |j                  d
                                         }	|	dvrt	          dd          |                                 d {V }
t%          |
          dk    rt	          dd          dt'                      v rt(          nt*          dz  dz  dz  }t          j        |d           t/          j        dd|          pd}| d| dt3          j        d           |	 }||z  }t7          |d          5 }|                    |
           d d d            n# 1 swxY w Y   d| }i }|                                D ]-\  }}t          |t                    rt=          |          ||<   .|r$||d	<   t          |t                    r
|j        |d<   t?                      5 }|                     d|!                                |!                                ||tE          j#        |          f           |$                                 d d d            n# 1 swxY w Y   dtJ          j&        '                    |           }tQ          d||d          S )Nr   rz   rv   zEl email es obligatorio.rr      )hoursr   playerPhotor!   z.pngz.jpgz.jpegz.webp:Formato de imagen no permitido. Usa PNG, JPG, JPEG o WebP.i   u,   La imagen supera el tamaño máximo de 10MB.UPLOADS_DIRr   r   r   Texist_okz
[^a-z0-9]+-r   r   wbz/static/uploads/academy/playerPhoto_originalzcINSERT INTO "formulario-registro"(created_at, expires_at, email, pin, data_json) VALUES (?,?,?,?,?)z/complete-registration?email=)okr   redirect))formr   r   r   r	   r   r   r   r   	timedeltar   
isinstancer   filenameospathsplitextreadr   globalsr   BASE_DIRmakedirsresubr   	token_hexopenwriteitemsrd   r[   r6   r   jsondumpsrT   urllibparsequoter   )rh   r  r   now	ttl_hoursexpr   saved_photo_publicplayer_photoextcontentuploads_dir
email_slugr  	file_pathfdatakvr8   r  s                        r&   r   r   D  s     D XXg$"++--3355E P4NOOOO 
+



CI
9---
-C
a
 
 C 88M**L,
++ C0E Cg|455a8>>@@888C8tuuuu$))++++++++w<<***C8fgggg &3gii%?%?kkhQYFY\eFehqFq
K$//// VM366@&
 DD3DD):1)=)=DsDD(*	 )T"" 	aGGG	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 CBB D

  1a$$ 	a&&Q A0]lJ// 	A+7+@D'( 
 Dq]]__cmmoouc4:d;K;KL	
 	
 	
 	               Kv|/A/A%/H/HJJHtCXFFGGGs%   H..H25H26A&L((L,/L,z/complete-registrationcomplete_registration_getc                 h   K   t          |           }t                              d| |pd|d d          S )Ncomplete-registration.htmlrz   rh   r   r   r   r   )rh   r   re   s      r&   r)  r)    sA      	g		B%%$u{R$OO  r)   complete_registration_postr   c                 	  K   |pd                                                                 }t          |           }t          j                                                                        }t                      5 }|                    d||                                 f          	                                }	|	s,t                              d| ||dd          cd d d            S |	d         |k    r,t                              d| ||dd          cd d d            S t          |          }
|
rZ|r,t          |d                   t          |
d                   k    r,t                              d| ||d	d          cd d d            S |
sw|r|rt          |          d
k     r,t                              d| ||dd          cd d d            S t          |                                 ||d           t          |          }
t          |
d                   }t!          j        |	d                   fd}i d |dd          d |d          d |dd          d |d          d |dd          d |ddd          d |d          d |ddd          d |d           d! |d!          d" |d"          d# |d$          d% |d&          d' |d(          d) |d)          d* |d*          d+ |d+           |d,           |d-           |d.           |d/           |d0           |d1           |d2d3          d4}g }g }|                                D ]5\  }}|                    | d5| d6           |                    |           6|                    |           	 |                    d7d8                    |           d9|           n# t*          $ r Y nw xY w|                    d:||	d         |f           |                    d;|t          |	d                   f           |                    d<t          |	d                   f           |                                 d d d            n# 1 swxY w Y   || j        d=<   |
d>         | j        d><   t1          |                     d?          d@A          S )BNrz   zLSELECT * FROM "formulario-registro" WHERE email = ? AND pin = ? AND used = 0r+  u   PIN inválido o no encontrado.r,  
expires_atz)El PIN ha expirado. Repite el formulario.ru   uY   Ese email ya tiene una cuenta. Inicia sesión con ese email y vuelve a introducir el PIN.r   uL   Completa nombre y una contraseña (mín. 6 caracteres) para crear tu cuenta.r   r   	data_jsonc                  L    | D ]}                     |          }|dvr|c S  d S )N)Nrz   null)r   )keysr'  r(  	form_datas      r&   pickz(complete_registration_post.<locals>.pick  sB      MM!$$...HHH /4r)   r,   whatsappr=   r?   	birthDater@   r-   r   r/   currentTeamclubr0   r1   currentPositionpreferredPositionrA   dominantFootrB   rC   rD   trainingTyperE   physicalWorkrF   physicalWorkDetailsrG   rH   rI   	chestPainrK   whatsappContentvideoPermissionprivacyAcceptancedataConfirmationinjuryHistoryr2   )rJ   rK   rL   rM   rN   rO   r2   z = COALESCE(?, )zUPDATE users SET , z WHERE id = ?zQINSERT INTO academy_registrations (user_id, data_json, created_at) VALUES (?,?,?)zCUPDATE "formulario-registro" SET used = 1, used_at = ? WHERE id = ?z.DELETE FROM "formulario-registro" WHERE id = ?ri   r*   r   rm   rn   )r   r   r|   r   r   r   r   r[   r6   r_   r   r   r   r`   r   r   r  loadsr  appendr   r~   rT   r   r   r   )rh   r   r   r   r   r   re   now_isor8   r%   r;   ri   r5  update_valscols_sqlparamscolvalr4  s                     @r&   r-  r-    s      +2$$&&,,..J	g		Bk  "",,..G	 nDllZ%
 
 (** 	
  	--,#j"Oopp n n n n n n n n |''--,#j"Oz{{ n n n n n n n n& %Z00  	R 	3r$x==C4G4G#G#G--,#j"uw w /n n n n n n n n<  	5 x 3x==1+<+< 110 '*bln n An n n n n n n nJ 

j(JJJJ(44Hhtn%% Js;/00		 	 	 	 	
TT':%>%>
 TT%[[
 TT+|%D%D	

 TT&\\
 TT-%B%B
 TT-%H%H
 TT*%5%5
 TT*;=PR\%]%]
 TT.%9%9
 TT+%6%6
 TT,%7%7
 TT.%9%9
" TT.%9%9#
$ $TT*?%@%@%
& TT)__'
( TT)__)
* TT*%5%5+
, &*T+%6%6%)T,%7%7%)T*;%<%<%)T*;%<%<%)T*=%>%>%)T*<%=%=%)T/;K%L%L=
 
 
D #))++ 	 	HCOOs993999:::MM#g	LLOTYYx-@-@OOOQWXXXX 	 	 	 D	 	_c+&0	
 	
 	
 	Z]dfijmnrjsftft\uvvvECPTIGXYYY]n n n n n n n n n n n n n n nb ")GOI&v.GOF < <#NNNNsR   9AR	$+R	AR	8R	G*R	7-O%$R	%
O2/R	1O22BR		RRz/info-usuariosc                    K   t          |           }|s$t          |                     d          d          S t                              d| |d          S )Nr   rm   rn   zinfo-usuarios.htmlr   r|   r   r   r   r   r   s     r&   info_usuariorR    sf      	g		B OGOOG$<$<#NNNN%%&:= =   r)   z
/dashboardr   c                    K   t          |           }|s$t          |                     d          d          S t                              d| |d          S )Nr   rm   rn   zdashboard.htmlr   rQ  r   s     r&   r   r   !  s[      	g		B OGOOG$<$<#NNNN%%&6GUW8X8XYYYr)   r{   c                    K   t          |           }|st          dd          S t                              d| |d          S )Nrl   rm   rn   z
admin.htmlr   r|   r   r   r   r   s     r&   rc   rc   (  sM        D ?H#>>>>%%lQU4V4VWWWr)   z/make-me-adminc                 b  K   t          |           }|st          ddid          S t          j        t                    5 }|                    dt          |d                   f           |                                 d d d            n# 1 swxY w Y   t          dd|d	          d
i          S )Nr   No autenticado  )rp   z*UPDATE users SET role='admin' WHERE id = ?ru   messagezUsuario r   z ahora es admin)r|   r   rP   rQ   rR   r6   r`   rT   )rh   re   r8   s      r&   make_me_adminrZ  /  s      	g		B JW&67SIIII		!	! TAC4MMCSTTT               $Jr&z$J$J$JKLLLs    ?BBBr   notificacionesc                   K   t          |           }|st          dd          S t          |d                   }d}|U	 t          |          }n# t          $ r d}Y nw xY w|r0|d         dv r&t	          |          }|rt          |d                   }t          |          }g }|d         dv rH|r$t          t          |d                   |          }n"t          t          |d                             }g }|d         dv rt                      }d fd	|pg D             }g }	i }
g }|rt          j
        t                    5 }t          j        |_        |                    d
|f                                          }	ddd           n# 1 swxY w Y   fd|	pg D             }fd|	pg D             }
t                               d| ||rt%          |          nd|||||	||
d
          S )z
    Por defecto muestra TU bandeja.
    Si `user_id` viene en la query y eres docente/admin, muestra la bandeja de ese alumno
    y las enviadas del docente filtradas a ese alumno.
    rl   rm   rn   ru   Nr*   r   c                      	  fd                                  D             S # t          $ r t                     cY S w xY w)Nc                 "    i | ]}||         S r"   r"   )r$   r'  rs     r&   
<dictcomp>z8notificaciones.<locals>._row_to_dict.<locals>.<dictcomp>l  s    ...Aqt...r)   )r3  r~   r   )r_  s   `r&   _row_to_dictz$notificaciones.<locals>._row_to_dictj  sT    	....QVVXX.... 	 	 	77NNN	s   # ??c                 &    g | ]} |          S r"   r"   )r$   nra  s     r&   
<listcomp>z"notificaciones.<locals>.<listcomp>p  s!    AAAa,,q//AAAr)   z
                SELECT id, user_id, date, time, duration_minutes, status, created_at, name, email, phone, notes, price_cents
                FROM reservations
                WHERE user_id = ?
                ORDER BY date ASC, time ASC
            c                 &    g | ]} |          S r"   r"   r$   ara  s     r&   rd  z"notificaciones.<locals>.<listcomp>  s!    KKK\\!__KKKr)   c                 N    i | ]!}t          |d                     |          "S )ru   )r`   rf  s     r&   r`  z"notificaciones.<locals>.<dictcomp>  s-    XXXaC$LL,,q//XXXr)   znotificaciones.html)
rh   r   	view_usernotificationssent_notificationsr   notifications_jsonappointmentsappointments_jsonappointments_map)r|   r   r`   r~   r}   r   r   r   r   rP   rQ   rR   rX   rY   r6   r7   r   r   r   )rh   ri   re   target_user_idri  inboxsentr   rl  rm  ro  rn  r8   ra  s                @r&   r[  r[  A  s      
g		B ?H#>>>>D]]NI	'llGG 	 	 	GGG	  	6r&z%999&w//I 6!$Yt_!5!5 '~66E D	&z))) 	A9#bh--XXDD1#bh--@@DH	&z)))>>   BAAAEKRAAA L 
Y_W%% 	/&{D<< )
 !"$ $
 %-HJJ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ LKKK|7IrKKKXXXXLDVTVXXX %%,5?i4""& "4(!2 0	
 	
  s$    A AA;FFFrx   create_notificationr   bodyreservation_idc           
      B  K   t          |           }|st          dd          S |d         dvrt          dd          |pd	                                }|pd	                                }|r|st          d
d          	 t	          |          }n# t
          $ r t          d
d          w xY wd }| t          |                                          d	k    r	 t	          |          }n# t
          $ r t          d
d          w xY wt          j        t                    5 }t          j
        |_        |                    d|f                                          }	|	st          dd          t	          |	d         pd          |k    rt          d
d          	 d d d            n# 1 swxY w Y   t          j        t                    5 }|                    dt          j                                                                        t	          |d                   ||||f           |                                 d d d            n# 1 swxY w Y   |r6t'          |          }
|
j        d	k    r|
j        d	k    rt          |d          S t          dd          S )Nrl   rm   rn   r*   r   rq   z3Solo docentes o admin pueden enviar notificaciones.rr   rz   rv   u#   Título y mensaje son obligatorios.u   Destinatario inválido.u   Reserva inválida.z1SELECT id, user_id FROM reservations WHERE id = ?rt   zReserva no encontrada.ri   r   z/La reserva no pertenece al alumno seleccionado.z
            INSERT INTO notifications (created_at, sender_id, recipient_id, title, body, is_read, reservation_id)
            VALUES (?, ?, ?, ?, ?, 0, ?)
            ru   r   )r|   r   r	   r   r`   r~   rd   rP   rQ   rR   rX   rY   r6   r_   r   r   r   r   rT   ry   r   r   )rh   r   r   rt  rj   ru  re   res_id_to_saver8   resparseds              r&   rs  rs    sx      
g		B ?H#>>>>	&z---4ijjjj[b!!EJBD [ [4YZZZZO<(( O O O4MNNNNO N!c.&9&9&?&?&A&AR&G&G	N 00NN 	N 	N 	NC8LMMMM	N_W%% 		o&{D,,C!  hjj   V#<TUUUU3y>&Q''<77#<mnnnn 8		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 		o 
	!	! T [!!++--s2d8}}lESWYgh	
 	
 	
 	                C(##=B6=B#6#6#cBBBB  1sCCCCs>   B B.C, ,D$A:F++F/2F/A2IIIz/api/teachersapi_teachersc                 8  K   t          |           }|st          dd          S t          j        t                    5 }t          j        |_        |                    d          }d |                                D             }d d d            n# 1 swxY w Y   |S )Nrl   rm   rn   z\SELECT id, name, email, created_at, role FROM users WHERE role = 'docente' ORDER BY name ASCc                 ,    g | ]}t          |          S r"   r   r$   r_  s     r&   rd  z api_teachers.<locals>.<listcomp>      000AQ000r)   	r|   r   rP   rQ   rR   rX   rY   r6   r7   rh   r   r8   r:   r&  s        r&   rz  rz    s         D ?H#>>>>		!	! 1T";llj
 
 100001 1 1 1 1 1 1 1 1 1 1 1 1 1 1 K   ABBB>   rc   r   r   c                       e Zd ZU eed<   dS )
RoleUpdater*   N)__name__
__module____qualname__rd   __annotations__r"   r)   r&   r  r    s         
IIIIIr)   r  c                     t          j        t                    5 }|                    d|| f           |                                 d d d            d S # 1 swxY w Y   d S )Nz&UPDATE users SET role = ? WHERE id = ?)rP   rQ   rR   r6   rT   )ri   r*   r8   s      r&   set_user_roler    s    		!	! T=gOOO                 s   -AAAz
/api/users	api_usersc                 8  K   t          |           }|st          dd          S t          j        t                    5 }t          j        |_        |                    d          }d |                                D             }d d d            n# 1 swxY w Y   |S )Nrl   rm   rn   an  SELECT id, name, email, created_at, role, phone, avatar, dni, birth_date, city, dominant_foot, team, category, position, injury_history, strengths, weaknesses, training_type, physical_work, physical_work_details, smoking, alcohol, recovery, chest_pain, discomfort, whatsapp_content, video_permission, privacy_acceptance, data_confirmation FROM users ORDER BY id DESCc                 ,    g | ]}t          |          S r"   r}  r~  s     r&   rd  zapi_users.<locals>.<listcomp>  r  r)   r  r  s        r&   r  r    s         D ?H#>>>>		!	! 1T";ll  L  M  M000001 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Kr  z/api/users/{user_id}/roleapi_users_set_rolepayloadc                   K   t          |          }|st          dd          S t          t          |d                             }|r+t	          |d                                                   dk    rt          dd	          t          |           }|st          d
d	          |j        pd                                                                }|t          vrt          dd	          t	          |d                                                   }|dk    }|o|dk    }	||k    rd| |ddS |	r%t                      }
|
dk    rt          dd	          t          | |           d| |ddS )Nrl   rm   rn   ru   r*   rc   rq   z%No tienes permisos para cambiar rolesrr   rt   r   rz   rv   u   Rol inválidoTF)r  ri   r*   changedr!   uT   Debe existir al menos un usuario con rol admin. No puedes degradar al último admin.)r|   r   r}   r`   rd   r   r	   r*   r   ALLOWED_ROLESra   r  )ri   r  rh   re   me_rowr   new_rolecurrent_role	was_adminis_demoting_adminadmins_counts              r&   r  r    s     	g		B ?H#>>>>C4MM**F ]S((..00G;;4[\\\\G$$F M4KLLLL"))++1133H}$$ODDDDvf~&&,,..L'I!9h'&9 xwUSSS  #~~1m    '8$$$7HNNNr)   )OptionalDictAny	Annotated)r   )r   )r   FieldStringConstraints)Queryz^\d{4}-\d{2}-\d{2}$)patternz^\d{2}:\d{2}$c                   
   e Zd ZU eed<   eed<    eddd          Zeed<    edd	          Z	eed
<   dZ
ee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dS )ReservationIndatetime<        geleduration_minutesr   r  price_centsNri   r   r   r,   
confirmadastatusnotes)r  r  r  DateStrr  TimeStrr  r  r`   r  ri   r  r   rd   r   r,   r  r  r"   r)   r&   r  r  <  s         
MMM
MMM!E"u555c555uQ1~~~K%%%!GXc]!!!D(3-E8C=E8C=(FHSM(((E8C=r)   r  c                   B   e Zd ZU dZee         ed<   dZee         ed<    e	ddd          Z
ee         ed<    e	dd	          Zee         ed
<   dZee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dZee         ed<   dS )ReservationUpdateNr  r  r  r  r  r  r   r  r  ri   r   r   r,   r  r  )r  r  r  r  r  r  r  r  r  r  r  r`   r  ri   r   rd   r   r,   r  r  r"   r)   r&   r  r  H  s         "D(7
""""D(7
"""&+eDQ5&A&A&AhsmAAA!&t!2!2!2K#222!GXc]!!!D(3-E8C=E8C= FHSM   E8C=r)   r  )r  r  r  List)r  z/api/public/availabilityi  i  r  r!      08:0022:00x   yearmonth	date_fromdate_to	open_time
close_timeslot_minutesc                 .  K   | r|r~t          | |d          }|dk    rt          | dz   dd          }nt          | |dz   d          }|                                }|t          j        d          z
                                  }|r|st	          dd          d}	t          j        t                    5 }
t
          j        |
_	        |

                    |	||f                                          }d d d            n# 1 swxY w Y   i }|D ]V}|d         }|                    |g                               |d	         t          |d
                   |d         d           Wt          ||          }i }|                                D ]H\  }}i }|D ]6}t#          |          t%          fd|D                       }|rdnd||<   7||d||<   I	 t          j                            |          }t          j                            |          }||z
  j        dz   }t-          |          D ]B}|t          j        |          z                                   }||vrd |D             g d||<   Cn# t.          $ r Y nw xY wt1          |ddi          S )Nr!   r  )daysrv   z,Proporciona year+month o date_from y date_torr   z
      SELECT date, time, duration_minutes, status
      FROM reservations
      WHERE date >= ? AND date <= ?
        AND status != 'cancelada'
      ORDER BY date ASC, time ASC
    r  r  r  r  )r  r  r  c           
   3      K   | ]<}t          t          |d                    t          |d                             V  =dS )r  r  N)_overlap_to_minutesr`   )r$   bs_startr  s     r&   r   z&public_availability.<locals>.<genexpr>  sN      }}qr'<QvY9O9OQTUVWiUjQkQkll}}}}}}r)   occupied	available)slotsbusy_blocksc                     i | ]}|d S )r  r"   )r$   ss     r&   r`  z'public_availability.<locals>.<dictcomp>  s    $I$I$Ia$I$I$Ir)   zCache-Controlzpublic, max-age=30)headers)date_clsr   r   r  r	   rP   rQ   rR   rX   rY   r6   r7   
setdefaultrI  r`   generate_daily_slotsr  r  anyr  fromisoformatr  r   r~   r   )r  r  r  r  r  r  r  startendsqlr8   rowsbusyr_  d	std_slotsoutdayblocksslot_statesr  s_busystart_dend_ddeltair  s         `                   @r&   public_availabilityr  _  sl       ; ;ua((B;;461a((CC4q!,,COO%%	1----88:: dG d4bccccC 
	!	! BT";||C)W!566??AAB B B B B B B B B B B B B B B
 -/D  fI2%%fI #A&8$9 : :k'
 '
 	 	 	 	 %Y
LIII &(Czz|| 	
 	
V 	C 	CA!!nnG}}}}}v|}}}}}F+1BZZ{KNN !
 
C	'''	22'''007?(1,u 	_ 	_A2<Q////::<<A||$I$Ii$I$I$IZ\^^A	_     -&    s%   7<C??DDBI4 4
J J)r   r  r  c                 `    t          t          |                     d                    \  }}||fS )N:)mapr`   split)r  hms      r&   _parse_hhmmr    s(    sAGGCLL!!DAqa4Kr)   hhmmc                 6    t          |           \  }}|dz  |z   S )Nr  )r  )r  r  r  s      r&   r  r    s     tDAqR4!8Or)   a_starta_durb_startb_durc                 (    | |z   |k    p||z   | k     S r   r"   )r  r  r  r  s       r&   r  r    s"    %7*Hgo.HIIr)   Z   c                     t          |           }t          |          }g }|}||z   |k    r4|dz  }|dz  }|                    |dd|d           ||z  }||z   |k    4|S )Nr  02dr  )r  rI  )		open_hhmm
close_hhmmr  r  r  r  tr  r  s	            r&   r  r    s    	""E
##C
CA
l
c
!
!GRQ

a%%%a%%%&&&	\ l
c
!
! Jr)   c                 ^   t          |           }|st          dd          t          |t          j                  r6d|                                v r|d         t          |d                   nd}n#t          |                    dd                    }|dk    rt          dd          |S )	NrX  rW  rr   r*   rz   rc   rq   zSolo administradores)r|   r	   r  rP   rX   r3  rd   r   )rh   re   r*   s      r&   require_adminr    s    	g		B F4DEEEE "gk"" '"(BGGII"5"5"V*:Ps2f:VX266&"%%&&w4JKKKKIr)   r%   c                     | d         | d         | d         | d         | d         | d         | d         | d         | d	         | d
         | d         | d         dS )Nru   
created_atr  r  r  r  r   r   r,   r  ri   r  )ru   r  r  r  r  r  r   r   r,   r  ri   r  r"   )r%   s    r&   _reservation_row_to_dictr    si    $i,'FF 23=)FWWWy>h-  r)   z/api/reservations)response_modelc                   K   t          |            	 t          j        |j        d           n# t          $ r t          dd          w xY w|j        r)t          |j                  dk     s|j        d         dk    rt          dd          	 t          |j        d d                   }t          |j        d	d                   }n# t          $ r t          dd          w xY wd
|cxk    rdk     rn nd
|cxk    rdk     sn t          dd          |d
k    r|d
k    rt          dd          d|cxk    rdk     sn t          dd          |j	        |j	        d
k    rt          dd          |j	        dk    rt          dd          |j
        }|j        }|j        }|j        rt          j        t                     5 }t          j        |_        |                    d|j        f                                          }|st          dd          |s|d         }|s|d         }d d d            n# 1 swxY w Y   t          j                                        d          }		 t          j        t                     5 }t          j        |_        |                    d|	|j        |dd|d|j	        |j        ||||j        |j        |j        pdf          }
|
j        }|                                 |                    d|f                                          }d d d            n# 1 swxY w Y   n+# t          j        $ r}t          dd |           d }~ww xY wt;          |          S )!Nz%Y-%m-%drv   u(   Fecha inválida. Usa formato YYYY-MM-DD.rr   r     r  u"   Hora inválida. Usa formato HH:MM.   r   r     u   Hora inválida.z,No se admiten reservas a medianoche (00:00).      u&   Hora fuera de horario (08:00–22:00).u   Duración inválida.r  u   Duración demasiado larga.,SELECT id, name, email FROM users WHERE id=?rt   r   r   r   seconds)timespecz
                INSERT INTO reservations (created_at, date, time, duration_minutes, price_cents,
                                          name, email, phone, notes, user_id, status)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            r  r  %SELECT * FROM reservations WHERE id=?zError al crear: )r  r   strptimer  r~   r	   r  r   r`   r  r   r   r,   ri   rP   rQ   rR   rX   rY   r6   r_   r   r   r  r  r  	lastrowidrT   IntegrityErrorr  )rh   r  hhmmr   r   r,   r8   ur  r:   ridr%   es                 r&   api_reservations_creater    s     '`',
3333 ` ` `4^____` < Z3w|,,q00GLOs4J4J4XYYYYZbqb!""ac"## Z Z Z4XYYYYZ LLLLbLLLLLQ"\\\\r\\\\4EFFFF 
Qww2774bccccLLLLbLLLL4\]]]] '7+Cq+H+H4JKKKK$&&4PQQQQ <DMEME 
#_W%% 		#&{DKgoM_``iikkA U#<STTTT !y #'
		# 		# 		# 		# 		# 		# 		# 		# 		# 		# 		# 		# 		# 		# 		# "",,i,@@JL_W%% 	[&{D,,  
 $$$B$$$(#/<	 C" -CKKMMM,,FOOXXZZC+	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[ 	[, ! L L L4Jq4J4JKKKKL $C(((se   . A
8C C$A'H;;H?H?.L= BL1%L= 1L55L= 8L59L= =M%M  M%z/api/reservations/{res_id}res_idc                   K   t          |            d |                    d                                          D             }|st          dd          d|v r|d         rt	          j        t                    5 }t          j        |_        |	                    d|d         f          
                                }|st          d	d
          d|vs|                    d          s|d         |d<   d|vs|                    d          s|d         |d<   d d d            n# 1 swxY w Y   g }g }|                                D ]2\  }}	|                    | d           |                    |	           3|                    |           t	          j        t                    5 }t          j        |_        |	                    dd                    |           d|          }
|
j        dk    rt          d	d          |                                 |	                    d|f          
                                }d d d            n# 1 swxY w Y   t!          |          S )Nc                     i | ]\  }}||	S r"   r"   )r$   r'  r(  s      r&   r`  z+api_reservations_update.<locals>.<dictcomp>T  s    III1q!IIIr)   T)exclude_unsetrv   zNada que actualizarrr   ri   r  rt   r   r   r   z=?zUPDATE reservations SET rG  z WHERE id=?r   Reserva no encontradar  )r  r   r  r	   rP   rQ   rR   rX   rY   r6   r_   r   rI  r   rowcountrT   r  )rh   r  r  updatesr8   r  rU   valsr'  r(  r:   r%   s               r&   api_reservations_updater  Q  s     'II4 @ @ F F H HIIIG K4IJJJJ G	 2_W%% 	.&{DKgV_N`MbccllnnA U#<STTTTW$$GKK,?,?$"#F)g%%W[[-A-A%#$W: 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. DD  1qHHHAKK		!	! ZT";llRdiiooRRRTXYY<1C8OPPPPllBVINNWWYYZ Z Z Z Z Z Z Z Z Z Z Z Z Z Z $C(((s&   <BD$$D(+D((BIIIc                   K   t          |            t          j        t                    5 }t          j        |_        |                    d|f                                          }|st          dd          |                    d|f           |	                                 d d d            n# 1 swxY w Y   d|dS )Nr  rt   r  rr   z#DELETE FROM reservations WHERE id=?T)r  
deleted_id)
r  rP   rQ   rR   rX   rY   r6   r_   r	   rT   )rh   r  r8   r%   s       r&   api_reservations_deleter  w  s      '		!	! T";llBVINNWWYY 	QC8OPPPP:VIFFF               f---s   A9B00B47B4)r  r  r  c                   K   t          |            g }g }|r*|                    d           |                    |           |r*|                    d           |                    |           |*|                    d           |                    |           |r*|                    d           |                    |           |rdd                    |          z   nd}d| d	}t          j        t
                    5 }	t          j        |	_        |	                    ||          	                                }
d d d            n# 1 swxY w Y   d
 |
D             S )Nz	date >= ?z	date <= ?zuser_id = ?z
status = ?z WHERE z AND rz   z
        SELECT id, created_at, date, time, duration_minutes, price_cents,
               name, email, phone, notes, user_id, status
        FROM reservations
        z1
        ORDER BY date ASC, time ASC, id ASC
    c                 ,    g | ]}t          |          S r"   )r  r~  s     r&   rd  z)api_reservations_list.<locals>.<listcomp>  s!    666A$Q''666r)   )
r  rI  r   rP   rQ   rR   rX   rY   r6   r7   )rh   r  r  ri   r  whererM  clauser  r8   r  s              r&   api_reservations_listr"    s      'EF  ![!!!i    [!!!g]###g \"""f27?i',,u----RF 
	  C 
	!	! 4T";||C((11334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 766666s   :EEEz/api/meapi_mec                 N   K   t          |           }|st          ddi          S d S )NauthenticatedF)r|   r   r`   r   r   s     r&   r#  r#    s8      	g		B _e4555 r)   /perfilc                    K   t          |           }|st          dd          S t                              d| |d          S )Nrl   rm   rn   zprofile.htmlr   rU  r   s     r&   perfilr(    sM      	g		B ?H#>>>>%%n'SU6V6VWWWr)   /ajustesc                   K   t          |           }|st          dd          S t          j        t                    5 }t          j        |_        |                    d|d         f                                          }d d d            n# 1 swxY w Y   |rt          |          n|}t                              d| |d          S )Nrl   rm   rn   z
            SELECT
                id, name, email, phone, avatar, created_at,
                team, category, position, injury_history
            FROM users
            WHERE id=?
            ru   settings.htmlr   )r|   r   rP   rQ   rR   rX   rY   r6   r_   r   r   r   )rh   re   r8   	user_fullr   s        r&   ajustes_getr-    s     	g		B ?H#>>>> 
	!	! T";LL XK	
 	
 (** 	               #,3tIH%%o7T\7]7]^^^s   ABBBr,   r-   r/   r0   r1   r2   c	                 b  K   t          |           }	|	st          dd          S |pd                                }|pd                                }|pd                                pd }|pd                                pd }|pd                                pd }|pd                                pd }|pd                                pd }t          j        t
                    5 }
t          j        |
_        |
                    d|	d         f          	                                }|r|d         nd }d d d            n# 1 swxY w Y   |}|r5t          |dd           r#t          j                            |j                  d	                                         }|d
vrt                               d| |	dd          S t          j                            ddd          }t          j        |d           t          j                            |d|	d          |           }t)          |d          5 }|                    |                                 d {V            d d d            n# 1 swxY w Y   d|	d          | }	 t          j        t
                    5 }
|
                    d|||||||||	d         f	           |
                                 d d d            n# 1 swxY w Y   n4# t          j        $ r" t                               d| |	dd          cY S w xY wt          dd          S )Nrl   rm   rn   rz   z%SELECT avatar FROM users WHERE id = ?ru   r-   r  r!   r   r+  r   rh   r   r   appr   r   Tr   user_r  z/static/uploads/user_z
                UPDATE users
                SET name=?, email=?, phone=?, avatar=?, team=?, category=?, position=?, injury_history=?
                WHERE id=?
                u*   El correo ya está en uso por otra cuenta.r&  )r|   r   r   rP   rQ   rR   rX   rY   r6   r_   getattrr	  r
  r  r  r   r   r   r   r  r  r  r  rT   r  )rh   r   r   r,   r-   r/   r0   r1   r2   re   r8   r%   current_avataravatar_pathr   r"  r$  r%  s                     r&   ajustes_postr5    s"      
g		B ?H#>>>> JBD[b!!Ekr  ""*dEZR  (DDR&&((0DHR&&((0DH%+2244<N 
	!	! 8T";llBRXKPPYY[[*-7X48 8 8 8 8 8 8 8 8 8 8 8 8 8 8 !K >'&*d33 >gv//288::888--o"U@ @   
 gll5(I>>
K$////GLL.Ebh.E.E.EFF	)T"" 	)aGG&++--''''''(((	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) >bh===_W%% 		LL
 ue[$(N\^_c\de   KKMMM		 		 		 		 		 		 		 		 		 		 		 		 		 		 		 !   ))/A<
 <
   	 	 	 	s;;;;s[   "AD;;D?D?..I((I,/I,K, :K K,  K$$K, 'K$(K, ,.LLz/notesc                    K   t          |           }|st          dd          S t                              d| |d          S )Nrl   rm   rn   z
notes.htmlr   rU  r   s     r&   r  r  9  sX        D ?H#>>>>%%l5 5   r)   )r   TFplainc                     | pd} t           rt          j        |           S dt          j        |                     d                                                    z   S )Nrz   sha256$utf-8)_HAS_BCRYPTr   r   hashlibsha256encode	hexdigest)r7  s    r&   hash_passwordr@  Q  sP    KRE "{5!!!w~ell7&;&;<<FFHHHHr)   stored_hashc                    | pd} |pd}|                     d          s*|                     d          s|                     d          r0t          r'	 t          j        | |          S # t          $ r Y dS w xY wdS |                     d          rj|                    dd          d         }t          j        |                     d                    	                                }t          j        ||          S dS )	Nrz   z$2a$z$2b$z$2y$Fr9  r!   r:  )
startswithr;  r   r   r~   r  r<  r=  r>  r?  hmaccompare_digest)r7  rA  expecteddigests       r&   verify_passwordrH  X  s   KRE#Kf%% )?)?)G)G ;KaKabhKiKi  	}UK888   uuui(( 5$$Y2215W 5 566@@BB"684445s   A% %
A32A3z/ajustes/passwordcurrent_passwordnew_passwordconfirm_passwordc                   K   t          |           }|st          dd          S |pd                                }|pd                                }||k    rt                              d| |dd          S t          |          dk     rt                              d| |d	d          S t          |t                    r|                    d
          n|d
         }t          ||          st                              d| |dd          S t          |          }t          j        t                    5 }|                    d||d         f           |                                 d d d            n# 1 swxY w Y   t          dd          S )Nrl   rm   rn   rz   r+  u   Las contraseñas no coinciden.r/  r  u6   La nueva contraseña debe tener al menos 8 caracteres.r   u%   La contraseña actual no es correcta.z+UPDATE users SET password_hash=? WHERE id=?ru   r)  )r|   r   r   r   r   r   r  r   r   rH  r@  rP   rQ   rR   r6   rT   )rh   rI  rJ  rK  re   rA  new_hashr8   s           r&   ajustes_passwordrN  n  s      
g		B ?H#>>>> !&B--//L(.B5577'''))/5<
 <
   	 <1))/M<
 <
   	 .8D-A-AZ"&&)))r/GZK+[99 ))/<<
 <
   	 \**H		!	! TBXrRVxDXYYY               
<<<<s   13E00E47E4z/logoutc                 Z   K   | j                                          t          dd          S )Nr   rm   rn   )r   clearr   r   s    r&   logoutrQ    s-      O5555r)   z/api/healthc                     K   ddiS )Nr  r  r"   r"   r)   r&   healthrS    s      dr)   startupc                     	 t          j        t                    5 } |                     d           |                                  d d d            n# 1 swxY w Y   n# t
          $ r Y nw xY wt                       t                       d S )Nz
                UPDATE reservations
                SET name = (SELECT name FROM users WHERE users.id = reservations.user_id)
                WHERE (name IS NULL OR name='') AND user_id IS NOT NULL
            )rP   rQ   rR   r6   rT   r~   rV   r   rZ   s    r&   
on_startuprV    s    	_W%% 	LL    
 KKMMM	 	 	 	 	 	 	 	 	 	 	 	 	 	 	     IIIs4   A *AA AA AA 
A*)A*)r   )r   r   )r  r  r  )NNNN)fastapir   r   r   r   r   r   r	   fastapi.responsesr
   r   r   fastapi.staticfilesr   fastapi.templatingr   starlette.middleware.sessionsr   passlib.contextr   pydanticr   rP   pathlibr   r	  r  r0  Path__file__resolveparentr  rR   add_middlewarer   mountr   rV   r[   r`   ra   boolrf   postrd   rg   r   r}   r   r  r   r   r   r  r   r   r   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r)  r-  rR  r   rc   rZ  r[  ry   rs  rz  r  r  r  r  r  typingr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  tupler  r  r  r  r  rX   r  r   r  patchr  deleter  r"  r#  r(  r-  r5  r  r<  rD  passlib.hashr   r;  r~   r@  rH  rN  rQ  rS  on_eventrV  r"   r)   r&   <module>rm     s   Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q J J J J J J J J J J + + + + + + . . . . . . ; ; ; ; ; ; ( ( ( ( ( (       % % % % % % % % % % % % % % % % 				gK   7<!!))++2
\
!   $  8 8 8lH:&AAA 		)[[<888x	 H H HOo666	
I I IZ  "c " " " "
&D & & & &
 
&9:: 4994::.; .;.;.; Dj.; .; .; ;:.;lS    C     c #  C     + * * * * * * * * * * * * * * *      

 
 
C 
 
 
 
(' ( ( ( (       c    "c     *      
$+@AA  4994::&*d4jjFD FDFDFD DjFD
 tFD FD FD BAFDZ \**V V V V +*V ,//V V V V 0/V l33W    43 l33mW m m m 43m ==YW Y Y Y >=Y (lCC48DIIttTWyy S Sg Sc S S S S DCS. )LAAW    BA0 	CTUU3     VU0 :lCCn n n n DCn
 +OLII6:d3iiddSViiimimnqirir S S S S Scf S S S JIS: " ! ! ! ! ! * * * * * *	#9,WW    XW !I-	9 
$;<<DH DH DH DH =<DHL 	!(CT`aa W S4Z    ba 
")EVbcc ctCyytDzz4::@O @O@O@O 
@O
 *@O Dj@O @O @O dc@OD 	,77    87 KEEZW Z Z Z FEZ ,//X X X X 0/X 		M 	M 	M 	M 	M R Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q J J J J J J J J J J 	!1,OOR R' RC$J R R R PORn " ! ! ! ! !
"788 S		cS		4::!%d=D =D=D=D =D 	=D
 Dj=D $J=D =D =D 98=DF NKK    LK /..       3 c    
 lEE
W 
 
 
 FE
 
%,@AA%Oc %OJ %O %O %O %O BA%OT 2 1 1 1 1 1 1 1 1 1 1 1       * * * * * * 8 8 8 8 8 8 8 8 8 8           C**3IJJJJ
K
C**3CDDDD
E
  
  
  
  
 I 
  
  
 
  
  
  
  
 	 
  
  
 "       , , , , , , , , , , , , % % % % % %     	#$$%$777 5!333#!M M
3-MC=M }M c]	M M M M M M %$Mt ) ( ( ( ( ( ( (3 5S>    c c    Jc J# J JC JD J J J J
	 	 	 	 " ! ! ! ! ! 7    $'+ $sCx.    " 
d33O)7 O)] O) O) O) 43O)d '==")7 ")C ")J[ ") ") ") >=")J (>>	.7 	.C 	. 	. 	. ?>	. " ! ! ! ! ! ! !	T$Z88  $!! (7 (7(7}(7 c](7 c]	(7
 SM(7 (7 (7 98(7^ <h??'    @?( <00X' X X X 10X L11_w _ _ _ 21_2 *\22 S		cddT

DJJDJJ$t**H< H<H<
H< H< 	H<
 H< H< H< H< H< H< H< 32H<X ,//	 	 	 	 0/	  ######KK   KKKI I I I I I3 S T    (      
l;; !DIIS		 DII	-= -=-=-= -= 	-= -= -= <;-=f 6' 6 6 6 6    i    s   e ee