
    1i?>                        d dl Z d dl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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mZ d d	lmZ d d
lmZ d dlmZ d dl m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z' d dl(m)Z)  e jT                  e jV                  d       dD ]-  Z, e jZ                  e,      j]                  e jV                         /  e jZ                  e/      Z0defdZ1 e1       Z2y)    N)FastAPI)CORSMiddleware)delete)text)SQLAlchemyError)router)Base)engine)utcnow)PasswordResetToken)UserRefreshTokenVendor	ViolationProductScrapingResultSiteSettings)SchedulerServicez4%(asctime)s - %(name)s - %(levelname)s - %(message)s)levelformat)appzapp.serviceszapp.apireturnc                     t        d      } | j                  t        dgdddgdg       | j                  d      dd	       }| j                  d      dd
       }| j                  d      dd       }| j	                  t
        ddg       | j	                  t        dg       | j	                  t        ddg       | j	                  t        ddg       | j	                  t        ddg       | j	                  t               | S )NzMARCO Scraping)titlez#https://marco-fe.testyourapp.onlinez,^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$T*)allow_originsallow_origin_regexallow_credentialsallow_methodsallow_headersstartupc            	        K   	 t        j                         4 d {   } | j                  t        j                  j
                         d {    | j                  t        d             d {    | j                  t        t              j                  t        j                  t               k  t        j                  j                  d       z               d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d	             d {    | j                  t        d
             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d             d {    | j                  t        d              d {    | j                  t        d!             d {    | j                  t        d"             d {    | j                  t        d#             d {    | j                  t        d$             d {    | j                  t        d%             d {    | j                  t        d&             d {    | j                  t        d'             d {    | j                  t        d(             d {    | j                  t        d)             d {    | j                  t        d*             d {    | j                  t        d+             d {    | j                  t        d,             d {    | j                  t        d-             d {    d d d       d {    y 7 7 7 b7 7 7 7 7 {7 \7 =7 7 7 7 7 7 7 d7 E7 &7 7 7 7 7 7 l7 M7 .7 7 7 7 7 7 t7 U7 67 7 7 7 7 7 |7 ]7 >7 7 7 7 7 7 # 1 d {  7  sw Y   y xY w# t        $ r}t!        d.      |d }~ww xY ww)/NzQALTER TABLE users ADD COLUMN IF NOT EXISTS tokens_invalid_before TIMESTAMPTZ NULLzLALTER TABLE violations ADD COLUMN IF NOT EXISTS barcode_number VARCHAR(255);zJALTER TABLE violations ADD COLUMN IF NOT EXISTS reference_id VARCHAR(255);zUALTER TABLE violations ADD COLUMN IF NOT EXISTS confirmation_count INTEGER DEFAULT 1;z]ALTER TABLE violations ADD COLUMN IF NOT EXISTS source_type VARCHAR(50) DEFAULT 'registered';zUALTER TABLE violations ADD COLUMN IF NOT EXISTS last_confirmed_date TIMESTAMPTZ NULL;zVALTER TABLE violations ADD COLUMN IF NOT EXISTS notification_sent_at TIMESTAMPTZ NULL;zIALTER TABLE violations ADD COLUMN IF NOT EXISTS vendor_name VARCHAR(512);zIALTER TABLE violations ADD COLUMN IF NOT EXISTS marketplace VARCHAR(255);z<ALTER TABLE violations ALTER COLUMN vendor_id DROP NOT NULL;zBALTER TABLE scraping_results ALTER COLUMN vendor_id DROP NOT NULL;zIALTER TABLE violations ADD COLUMN IF NOT EXISTS price_difference NUMERIC;zNALTER TABLE violations ADD COLUMN IF NOT EXISTS percentage_difference NUMERIC;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_1_pack NUMERIC(10, 2) DEFAULT 0;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_2_pack NUMERIC(10, 2) DEFAULT 0;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_3_pack NUMERIC(10, 2) DEFAULT 0;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_4_pack NUMERIC(10, 2) DEFAULT 0;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_5_pack NUMERIC(10, 2) DEFAULT 0;zTALTER TABLE products ADD COLUMN IF NOT EXISTS price_6_pack NUMERIC(10, 2) DEFAULT 0;zUALTER TABLE products ADD COLUMN IF NOT EXISTS price_12_pack NUMERIC(10, 2) DEFAULT 0;zHALTER TABLE violations ADD COLUMN IF NOT EXISTS packs INTEGER DEFAULT 1;zQALTER TABLE products ADD COLUMN IF NOT EXISTS last_scraped_date TIMESTAMPTZ NULL;zOALTER TABLE products ADD COLUMN IF NOT EXISTS last_execution_time VARCHAR(255);zYALTER TABLE products ADD COLUMN IF NOT EXISTS scraping_status VARCHAR(50) DEFAULT 'idle';zSALTER TABLE products ADD COLUMN IF NOT EXISTS scraping_started_at TIMESTAMPTZ NULL;zUALTER TABLE products ADD COLUMN IF NOT EXISTS scraping_completed_at TIMESTAMPTZ NULL;zOALTER TABLE products ADD COLUMN IF NOT EXISTS scraping_error VARCHAR(500) NULL;zOALTER TABLE scraping_results ADD COLUMN IF NOT EXISTS domain_name VARCHAR(255);zZALTER TABLE site_settings ADD COLUMN IF NOT EXISTS scraping_enabled BOOLEAN DEFAULT FALSE;zbALTER TABLE site_settings ADD COLUMN IF NOT EXISTS scraping_frequency VARCHAR(50) DEFAULT 'daily';z\ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS scraping_time VARCHAR(5) DEFAULT '02:00';zCALTER TABLE site_settings ALTER COLUMN scraping_time DROP NOT NULL;zeALTER TABLE site_settings ADD COLUMN IF NOT EXISTS scraping_day_of_week VARCHAR(50) DEFAULT 'monday';zZALTER TABLE site_settings ADD COLUMN IF NOT EXISTS scraping_custom_cron VARCHAR(255) NULL;zYALTER TABLE site_settings ADD COLUMN IF NOT EXISTS enable_discovery BOOLEAN DEFAULT TRUE;zVALTER TABLE site_settings ADD COLUMN IF NOT EXISTS headless_mode BOOLEAN DEFAULT TRUE;zVALTER TABLE site_settings ADD COLUMN IF NOT EXISTS timeout_seconds INTEGER DEFAULT 15;zWALTER TABLE site_settings ADD COLUMN IF NOT EXISTS last_scheduled_run TIMESTAMPTZ NULL;z^ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS last_scheduled_run_status VARCHAR(50) NULL;z`ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS last_scheduled_run_summary VARCHAR(500) NULL;z]ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS client_timezone VARCHAR(50) DEFAULT 'UTC';zCALTER TABLE violations ADD COLUMN IF NOT EXISTS product_id INTEGER;a  
                        DO $$
                        BEGIN
                            IF NOT EXISTS (
                                SELECT 1 FROM information_schema.table_constraints 
                                WHERE table_name = 'violations' 
                                AND constraint_name = 'fk_violations_product_id'
                            ) THEN
                                ALTER TABLE violations 
                                ADD CONSTRAINT fk_violations_product_id 
                                FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE;
                            END IF;
                        END $$;
                        zOCREATE INDEX IF NOT EXISTS idx_violations_product_id ON violations(product_id);aA  
                        UPDATE violations v
                        SET product_id = p.id
                        FROM products p
                        WHERE v.product_id IS NULL
                        AND v.barcode_number IS NOT NULL
                        AND p.barcode = v.barcode_number;
                        zDatabase connection failed during startup. Check DATABASE_URL in .env (username/password/host/port/db) and ensure Postgres is running.)r
   beginrun_syncr	   metadata
create_allexecuter   r   r   where
expires_atr   used_atis_notr   RuntimeError)connes     ./var/www/html/marco-python-backend/app/main.py_create_tablesz"create_app.<locals>._create_tablesA   s>    L	||~ F FmmDMM$<$<===llZ   ll-.44+66&(B-55<<TBD   llfh   lldf  
 lloq   llwy   lloq   llpr   llce   llce  
 llV  
 ll\   llce   llhj   lln  
 lln  
 lln  
 lln  
 lln  
 lln  
 llo   llb   llkm  
 llik  
 lls   llm   llo   lli   llik  
 llt  
 ll|  
 llv   ll]  
 ll  
 llt  
 lls  
 llp  
 llp  
 llq  
 llx  
 llz  
 llw   ll]   ll  & lli   ll	  wF F F=






















&wF F F FN  	n 	s  ^]. []. -][!]/[0A-][!]?[ !]!["!][!]%[ &!][#!])[&*!][)!]-[,.!][/!]1[22!][5!]5[86!][;!]9[>:!]\!]=\>!]\ !]\
!]#\$!]\!]'\(!]	\
!]+\,!]\!]/\0!]\"!]3\%4!]\(!]7\+8!]\.!];\1<!]\4!]?\7 !]!\:"!]\=!]%] &!]]!])]*!]]	!]-].!]]!]1]2!]]!]5]6]:]. ]]. 
^]. ]]]]]] ]#]&])],]/]2]5]8];]>]]]]
]]]]]]]]"]%](]+].]1]4]7]:]=] ]]]	]]]]]]]. ]+]" ]+']. *^+]. .	^7^^^c                    K   t        j                  dd      j                         dv } | st        j	                  d       y	 t        j	                  d       t        j	                  d       t        j	                  d       t        j                          d{    y7 # t        $ r-}t        j                  d	t        |       d
       Y d}~yd}~ww xY ww)zGStart the scheduler when the app starts (only if ENABLE_SCHEDULER=true)ENABLE_SCHEDULERfalse)true1yesuH   [Scheduler] ⊘ Scheduler disabled (set ENABLE_SCHEDULER=true to enable)NzQ
================================================================================u5   🚀 [Scheduler] Starting scheduler at app startup...zP================================================================================u+   ❌ [Scheduler] Failed to start scheduler: T)exc_info)
osgetenvlowerloggerinfor   start_scheduler	Exceptionerrorstr)enable_schedulerr.   s     r/   _start_schedulerz$create_app.<locals>._start_schedulerQ  s     
 99%7AGGIMaaKKbc	`KK&KKOPKK"22444 	`LLFs1vhOZ^L__	`sB   ?CAB  BB  CB   	C)#CCCCshutdownc                     K   	 t        j                          d{    y7 # t        $ r+} t        j	                  dt        |               Y d} ~ yd} ~ ww xY ww)z*Stop the scheduler when the app shuts downNu-   ⚠️ [Scheduler] Error stopping scheduler: )r   stop_schedulerr>   r;   r?   r@   )r.   s    r/   _stop_schedulerz#create_app.<locals>._stop_schedulere  sJ     	S"11333 	SLLHQQRR	Ss6   A# !# A# 	A!AAAAz/authauth)prefixtagsvendors)rI   z/api/productsproductsz/api/violations
violationsz/api	dashboard)r   N)r   add_middlewarer   on_eventinclude_routerauth_routervendor_routerproduct_routerviolations_routerdashboard_routeradmin_settings_router)r   r0   rB   rF   s       r/   
create_apprW   +   s(   
(
)C - G%%  	 	\\)M M^ 	\\)` `& 	\\*S S {7&B}I;7~oZLQ(1B,X'k]K,-J    )3loggingr8   fastapir   fastapi.middleware.corsr   
sqlalchemyr   r   sqlalchemy.excr   app.api.routes.productsr   rS   app.api.routes.authrQ   app.api.routes.vendorsrR   app.api.routes.violationsrT   app.api.routes.dashboardrU   app.api.routes.admin_settingsrV   app.db.baser	   app.db.sessionr
   app.core.securityr   app.models.password_reset_tokenr   
app.modelsr   r   r   r   r   r   r   app.services.scheduler_servicer   basicConfigINFOlogger_name	getLoggersetLevel__name__r;   rW   r    rX   r/   <module>rq      s     	  2   * < 5 : A ? I  ! $ > c c c ;   
,,A
 6 :KGk"++GLL9: 
		8	$HG HT
 lrX   