
    3jg                       d 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mZ ddl	m	Z	 ddl
mZ dZdZd	Zd
Zg dZdZdZdZg dZg dZdZdZg dZddddZdZg dZdZdZg dZdZdZ g dZ!d d!d"d#Z"d$Z#d%Z$g d&Z%d'Z&g d(Z'd)Z(g d*Z)d+Z*d,Z+d-Z,g d.Z-d/Z.d0Z/dCd1Z0dDd2Z1dEd3Z2 ejf                  d4      Z4 ejf                  d5ejj                        Z6e G d6 d7             Z7dFd8Z8dFd9Z9dGd:Z:dHd;Z;dFd<Z<dId=Z= G d> d?      Z> G d@ dA      Z?dB Z@y)Ja  Storage backends. Two implementations, one interface:

  LocalStorage   - a folder on disk that mirrors the Drive job tree (dev / tests)
  DriveStorage   - the real shared Google Drive, via a service account

Both expose the same six calls. main.py never touches Drive directly.
    )annotationsN)	dataclass)datetime)PathDocsSignedzRegister.csvzCrew.txt)	timestampjobdocrevnamesigned_file
user_agentTake5zTake5-Register.csvzHazards.txt)idstartr
   r   taskhazardscontrolsotherr   r   finishqtyunitfinished_by)
)u%   Manual handling — bar, mats, boardszCTwo-man lifts on long or heavy gear. Cut to length before carrying.)u!   Cutting — cut-off saw / grinderzGGuard on, glasses and face shield, gloves, hearing. Clear the cut area.)zExposed reo endsz=Caps on every exposed bar end. No stepping over uncapped bar.)u$   Formwork — boards, props, step-upszBBraced and pegged before you let go. Nails punched. Fingers clear.)zOpen excavation / trench edgez>Edge protection stays in place. Approach from the access side.)zMobile plant nearbyzLOut of the swing radius. Eye contact with the operator. Spotter if entering.)zWet / slippery surfacezFThree points of contact. No running. Battery tools only on wet ground.)zWorking at height / edgez4Handrail or harness. No leaning out. Tools tethered.)zOther trades / publicz0Stay inside the fence. Watch gear on the ground.)zHeat / cold / hydrationz,Water on site. Speak up if you're not right.zIncident ReportszIncident-Register.csv)r   r	   r
   kindr   whatwherewhoaction
photo_filepdf_filer   followuptoolbox_dateu!   Hazard — I saw something unsafeu   Near miss — nearly went wrongu.   Incident — someone hurt or something damaged)hazardnearmissincidentzAttendance-Register.csv)r	   r
   r   eventlunchnotesourcedayfieldoldnewreasonby)07 - Site Documentsz
TM DocketszTM-Register.csv)r   r	   r
   dateseqdescriptionmenhourshours_totalplant	raised_by	signed_bycompany	signed_atr!   statuszMaterials-Register.csv	Materials)	r   r	   r
   r   itemphotor=   r0   r)   zgot it on siteorderedz
not needed)gotrA   z
not-needed)r1   z
Site DiaryzBoard-Register.csv)r	   r
   zonepersonr   detailr0   zDiary-Notes.csv)r	   sectiontextr0   z
Roster.csv)r2   rD   r
   r0   r	   r*   FleetzPlant-Register.csvzDefects.csv)r   r	   regovehicler   resultfailsr)   r@   r=   resolved_byresolved_at_signonzForeman.txtc                
   i }| xs dj                  d      D ]h  }|j                  d      \  }}}|j                         s)|j                         s:|j                         ||j                         j                         <   j |S )N ;:)split	partitionstriplower)rG   outpartk_vs         /opt/lfcs-signon/app/storage.pyparse_aliasesr^      sn    
C""3' /..%1a779%&WWYC	!"/ J    c                    | xs dj                         D ]\  }|j                         }|r|j                  d      r'|j                  d      \  }}}|j                         |j                         fc S  y)uE   Foreman.txt — one line, 'Matt Ryan | 0412 345 678'. Phone optional.rQ   #|rQ   rQ   )
splitlinesrV   
startswithrU   )rG   linenr[   ps        r]   parse_foremanri      sj    '') $zz|ts+..%1awwy!'')##$ r_   c                   g }| j                         D ]j  }|j                         }|r|j                  d      r'|j                  d      \  }}}|j	                  |j                         |j                         f       l |S )Nra   rb   )rd   rV   re   rU   append)rG   rX   rf   hr[   cs         r]   parse_hazardsrn      sq    
C! +zz|ts+..%1a

AGGIqwwy)*+ Jr_   z
^(\d{4})\bz\brev\s*([A-Za-z0-9.]+)c                  ,    e Zd ZU ded<   ded<   ded<   y)Docstrslotfilenamer   N)__name__
__module____qualname____annotations__ r_   r]   rp   rp      s    
IM	Hr_   rp   c                    t        |       j                  }t        j                  d|      }t	        j                  dd|j                               j                  d      S )NrQ   z
[^a-z0-9]+-)r   stem_REV_REsubrerW   rV   )rs   r{   s     r]   slot_ofr      sE    >D;;r4 D66-djjl399#>>r_   c                |    t         j                  t        |       j                        }|r|j	                  d      S dS N   rQ   )r|   searchr   r{   group)rs   ms     r]   rev_ofr      s/    tH~**+A1771:""r_   c                    t        j                  dd|      j                         }|ddt        | j                        j
                   d| dS )Nz	[^\w .-]+rQ   z%Y-%m-%d_%H%Mr[   .pdf)r~   r}   rV   r   rs   r{   )r   r   whensafes       r]   signed_filenamer      sI    66,D)//1D=!4#5#:#:";1TF$GGr_   c                    t         j                  d| xs d      j                         }t        j                  d|      D cg c]#  }|j                         s|j                         % }}|r|d   n| xs d}|j                         dd S c c}w )u   '2643 - Ford Civil - Wentworth Point CC4 Works' -> 'WENTWORTH POINT CC4 WORKS'.

    What goes in the roster message and on the board column. A bloke reads the place, not the
    client — nobody has ever asked "am I on Ford Civil tomorrow".
    rQ   u	   [-–—]N   )_JOB_REr}   rV   r~   rT   upper)folder_namer   spartstails        r]   short_labelr      sy     ;;r;,"-335D "t <J1	QWWYJEJ59K$52D::< Ks   BBc                    | j                         }|j                  d      ry|j                  d      ry|j                  d      ryy)Nr   application/pdfz.csvtext/csvz.pngz	image/png
image/jpeg)rW   endswith)rs   rg   s     r]   mime_forr      s>    Azz& zz&zz&r_   c                   |}| j                         r'| j                  dd      5 }t        t        j                  |      g       }ddd       r|D cg c]	  }||vs| }}|s|}n||k7  r||z   }| j                  dd      5 }t        j
                  |      D cg c]  }t        |       }	}ddd       | j                  ddd      5 }t        j                  ||d      }
|
j                          	D ]5  }|
j                  |D ci c]  }||j                  |      xs d c}       7 	 ddd       | j                          }| j                  ddd      5 }t        j                  ||d      }
|r|
j                          |
j                  |D ci c]  }||j                  |d       c}       ddd       y# 1 sw Y   xY wc c}w c c}w # 1 sw Y   *xY wc c}w # 1 sw Y   xY wc c}w # 1 sw Y   yxY w)	a  Append one row, widening the file first if we have gained a column since it was written.

    Registers written before adjustments existed have seven columns, not thirteen. Writing thirteen
    values under a seven-column header silently shears every row after it, so the file is rewritten
    with the wider header first. Every existing row survives; the new columns come out blank.
    rQ   utf-8newlineencodingNwignore
fieldnamesextrasactiona)existsopennextcsvreader
DictReaderdict
DictWriterwriteheaderwriterowget)pathheaderrowfieldsfexistingrm   missingrold_rowsr   rZ   r.   s                r]   
append_csvr      s    F{{}YYrGY4 	/CJJqM2.H	/"(>QAX,=q>G>!V#!G+YYrGY< D141BCAQCHCDYYsBYA JQqV(SAMMO% J

#HAAaB$6#HIJJ
 kkm
C	3W	5 8NN1hGMMO	

v6!Aswwq"~%67	8 8!	/ 	/ ?  DD D $I	J J 7	8 8sq    G	GGGG1G=G-G()	G- :G>G9
4G>GGG%(G--G69G>>Hc                  r   e Zd Zd-d.dZd/dZd0dZd1dZd2dZd3dZd4dZ	d5d	Z
d6d
Zd7dZd8dZd9dZd3dZd:dZd6dZd9dZd;dZd7dZd9dZd<dZd3dZd6dZd7dZd9dZd7dZd9dZd=dZed>d       Zd?d@dZ d6d Z!dAd!Z"d8d"Z#dBd#Z$dCd$Z%dDd%Z&dd&dEd'Z'dFdGd(Z(dFdHd)Z)dFdId*Z*dFdJd+Z+dFdKd,Z,y)LLocalStorageNc                H    t        |      | _        || _        |xs i | _        y N)r   rootsubpathaliases)selfr   r   r   s       r]   __init__zLocalStorage.__init__   s    J	}"r_   c                    t         j                  |      rgd| d| dfD ]X  }| j                  j                  |      D ]8  }|j	                         st         j                  |j
                        s4|c c S  Z y | j                  j                  |j                         |      j                         }dD ]U  }| j                  j                  |      D ]5  }|j	                         s||j
                  j                         v s1|c c S  W y )Nz*/*z*/*r   )	r   matchr   globis_dirr   r   r   rW   )r   job_nopatternrh   keys        r]   _job_dirzLocalStorage._job_dir   s     ==  NvhaL9 !0 !AxxzgmmAFF&; !! llv||~v6<<># 	GYY^^G, 88:#"7H	 r_   c                D    | j                  |      }|r|j                  S d S r   )r   r   )r   r   ds      r]   find_jobzLocalStorage.find_job  s!    MM&!qvv$$r_   c           	     ,   g t               }}dD ]  }t        | j                  j                  |            D ]  }|j	                         r)|j
                  |v s|j
                  j                  d      r=|| j                  z  j	                         s[|j                  |j
                         |j                  | j                  |j
                        |j
                  t        |j
                        d         |D cg c]
  }|d   s	| c}S c c}w )u  Every job folder that has a Sign-On folder in it. That IS the live list.

        No config file to fall out of step — a job goes live the moment someone drops a prestart in
        it, and drops off the board when the folder is archived. Two levels only, same as _job_dir.
        r   r[   r   r   labelr   )setsortedr   r   r   r   re   r   addrk   _key_forr   )r   rX   seenr   r   js         r]   	list_jobszLocalStorage.list_jobs  s     T# 	iGDIINN734 ixxzQVVt^qvv7H7H7MDLL(002 

4==#8!&&S^_`_e_eSfghi	i +a!E(+++s   ?
D
Dc                    t         j                  |      }|r|j                  d      S |j                         }| j                  j                         D ]  \  }}|j                         |v s|c S  y)zXThe bit that goes in a URL. Job number if it has one, else whichever alias points at it.r   rQ   r   r   r   rW   r   itemsr   r   r   lowrZ   r\   s         r]   r   zLocalStorage._key_for!  sg    MM+&771:!LL&&( 	DAqwwyC	 r_   c                    | j                  |      }|st        |      || j                  z  }|t        z  j	                  dd       |t
        z  j	                  dd       |S NT)parentsexist_ok)r   FileNotFoundErrorr   DOCSmkdirSIGNED)r   r   r   r   s       r]   rO   zLocalStorage._signon,  s_    MM&!#F++	
T5	
V4$7r_   c                z    | j                  |      t        z  }t        d |j                  d      D        d       S )Nc              3     K   | ]A  }t        t        |j                        |j                  t        |j                               C y wr   )rp   r   r   r   .0r   s     r]   	<genexpr>z)LocalStorage.list_docs.<locals>.<genexpr>8  s-     VaS!&&&.9Vs   AA	z*.pdfc                6    | j                   j                         S r   rs   rW   r   s    r]   <lambda>z(LocalStorage.list_docs.<locals>.<lambda>9  s    !****, r_   r   )rO   r   r   r   )r   r   docss      r]   	list_docszLocalStorage.list_docs5  s6    ||F#d*V499WCUV,
 	
r_   c                    | j                  |      D ]H  }|j                  |k(  s|| j                  |      t        z  |j                  z  j                         fc S  y r   )r   rr   rO   r   rs   
read_bytes)r   r   rr   r   s       r]   get_doczLocalStorage.get_doc<  sW    ' 	RAvv~4<</$6COOQQQ	R r_   c                p    | j                  |      t        z  |z  }|j                  |       t        |      S r   )rO   r   write_bytesrq   r   r   rs   datarh   s        r]   
put_signedzLocalStorage.put_signedB  s/    LL 6)H4	d1vr_   c                $   | j                  |      t        z  }|j                          }|j                  ddd      5 }t	        j
                  |t              }|r|j                          |j                  |       d d d        y # 1 sw Y   y xY w)Nr   rQ   r   r   r   )	rO   REGISTERr   r   r   r   REGISTER_HEADERr   r   )r   r   r   rh   r.   r   r   s          r]   append_registerzLocalStorage.append_registerG  sr    LL 8+((*nVVCgV6 	!q_=AJJsO		 	 	s   ?BBc                    | j                  |      t        z  }|j                         sg S |j                  d      j	                         D cg c]#  }|j                         s|j                         % c}S c c}w Nr   r   )rO   CREWr   	read_textrd   rV   )r   r   rh   ls       r]   get_crewzLocalStorage.get_crewP  s]    LL 4'xxzI#$;;;#@#K#K#M[aQRQXQXQZ	[[[s   A8#A8c                
   | j                  |      t        z  }|j                         sg S |j                  dd      5 }t	        j
                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY wNrQ   r   r   )rO   r   r   r   r   r   r   r   r   rh   r   r   s        r]   list_registerzLocalStorage.list_registerV  sm    LL 8+xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8   A9A4(A94A99Bc                \    | j                  |      t        z  }|j                  dd       |S r   )rO   TAKE5r   )r   r   ts      r]   _take5zLocalStorage._take5^  s*    LL 5(	t,r_   c                    | j                  |      t        z  }|j                         rt        |j	                  d            }|r|S t
        S r  )r  HAZARDSr   rn   r  DEFAULT_HAZARDS)r   r   rh   rB   s       r]   get_hazardszLocalStorage.get_hazardsc  sA    KK')88:W =>C
r_   c                b    | j                  |      |z  }|j                  |       t        |      S r   )r  r   rq   r   s        r]   	put_take5zLocalStorage.put_take5k  s*    KK(*	d1vr_   c                
   | j                  |      t        z  }|j                         sg S |j                  dd      5 }t	        j
                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY wr
  )r  TAKE5_REGISTERr   r   r   r   r   r  s        r]   _read_take5zLocalStorage._read_take5p  sm    KK.0xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8r  c                `   | j                  |      t        z  }|j                  ddd      5 }t        j                  |t
        d      }|j                          |D ]6  }|j                  t
        D ci c]  }||j                  |d       c}       8 	 d d d        y c c}w # 1 sw Y   y xY wNr   rQ   r   r   r   r   )	r  r  r   r   r   TAKE5_HEADERr   r   r   )r   r   rowsrh   r   r   r   rZ   s           r]   _write_take5zLocalStorage._write_take5w  s    KK.0VVCgV6 	D!q\QAMMO D

\BAquuQ|OBCD	D 	D C		D 	Ds   AB$2B	B$B$$B-c                l    | j                  |      }|j                  |       | j                  ||       y r   r  rk   r  )r   r   r   r  s       r]   append_take5zLocalStorage.append_take5  s.    'C&$'r_   c                $    | j                  |      S r   r  r   r   s     r]   
list_take5zLocalStorage.list_take5  s    ''r_   c                    | j                  |      }d}|D ]*  }|j                  d      |k(  s|j                  |       d}, |r| j                  ||       |S NFr   Tr  r   updater  )r   r   take5_idr   r  hitr   s          r]   finish_take5zLocalStorage.finish_take5  sa    ' 	AuuT{h& 	 fd+
r_   c                p    | j                  |      j                  t        z  }|j                  dd       |S r   )rO   parent	INCIDENTSr   r   r   rh   s      r]   
_incidentszLocalStorage._incidents  s0    LL '')3	t,r_   c                b    | j                  |      |z  }|j                  |       t        |      S r   )r2  r   rq   r   s        r]   put_incident_filezLocalStorage.put_incident_file  s*    OOF#h.	d1vr_   c                v   | j                  |      t        z  }|j                          }|j                  ddd      5 }t	        j
                  |t        d      }|r|j                          |j                  t        D ci c]  }||j                  |d       c}       d d d        y c c}w # 1 sw Y   y xY w)Nr   rQ   r   r   r   r   )
r2  INCIDENT_REGISTERr   r   r   r   INCIDENT_HEADERr   r   r   )r   r   r   rh   r.   r   r   rZ   s           r]   append_incidentzLocalStorage.append_incident  s    OOF#&77((*nVVCgV6 	E!q_8TAJJ?Ca3771b>)CD		E 	E D		E 	Es   AB/ B*
B/*B//B8c                
   | j                  |      t        z  }|j                         sg S |j                  dd      5 }t	        j
                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY wr
  )r2  r6  r   r   r   r   r   r  s        r]   list_incidentszLocalStorage.list_incidents  sn    OOF#&77xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8r  c                R    t        | j                  |      t        z  t        |       y r   )r   rO   ATTENDANCE_REGISTERATTENDANCE_HEADER)r   r   r   s      r]   append_attendancezLocalStorage.append_attendance  s    4<<'*==?PRUVr_   c                
   | j                  |      t        z  }|j                         sg S |j                  dd      5 }t	        j
                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY wr
  )rO   r<  r   r   r   r   r   r  s        r]   list_attendancezLocalStorage.list_attendance  sn    LL #66xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8r  c                    | j                  |      t        z  }|j                         rt        |j	                  d            S dS )Nr   r  rc   )rO   FOREMAN_FILEr   ri   r  r1  s      r]   get_foremanzLocalStorage.get_foreman  s8    LL </?@xxz}Q[['[:;WxWr_   c                x    t        d | j                  j                  dd      j                  d      D              S )Nc              3  &   K   | ]	  }|s|  y wr   rx   )r   xs     r]   r   z,LocalStorage.signon_parts.<locals>.<genexpr>  s     P1aQPs   \/)tupler   replacerT   r   s    r]   signon_partszLocalStorage.signon_parts  s/    P 4 4T3 ? E Ec JPPPr_   Tc                    | j                  |      }|st        |       |j                  | }|r|j                  dd       |S r   )r   r   joinpathr   )r   r   r   creater   rh   s         r]   _underzLocalStorage._under  sH     MM&!#F++AJJGGD4G0r_   c                d    | j                  ||      |z  }|j                  |       t        |      S r   )rP  r   rq   )r   r   r   rs   r   rh   s         r]   put_job_filezLocalStorage.put_job_file  s,    KK&1	d1vr_   c                t    | j                  ||d      |z  }|j                         r|j                         S d S NFrO  )rP  r   r   )r   r   r   rs   rh   s        r]   get_job_filezLocalStorage.get_job_file  s4    KKeK4x?!"q||~55r_   c                    | j                  ||d      }|j                         r t        d |j                         D              S g S )zVFilenames only. The diary needs to know what is in today's photo folder, nothing more.FrU  c              3  V   K   | ]!  }|j                         s|j                   # y wr   )is_filer   r   s     r]   r   z.LocalStorage.list_job_files.<locals>.<genexpr>  s     AQYY[affAs   )))rP  r   r   iterdir)r   r   r   rh   s       r]   list_job_fileszLocalStorage.list_job_files  s;    KKeK4EFXXZvAaiikAAWUWWr_   c                   | j                  ||d      |z  }|j                         sg S |j                  dd      5 }t        j                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY w)NFrU  rQ   r   r   )rP  r   r   r   r   r   )r   r   r   rs   rh   r   r   s          r]   read_job_csvzLocalStorage.read_job_csv  ss    KKeK4x?xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8s   A8A3'A83A88Bc                D    t        | j                  ||      |z  ||       y r   )r   rP  )r   r   r   rs   r   r   s         r]   append_job_csvzLocalStorage.append_job_csv  s    4;;vu-8&#Fr_   c                L   | j                  ||      |z  j                  ddd      5 }t        j                  ||d      }|j	                          |D ]5  }|j                  |D 	ci c]  }	|	|j                  |	      xs d c}	       7 	 d d d        y c c}	w # 1 sw Y   y xY wr  )rP  r   r   r   r   r   r   )
r   r   r   rs   r   r  r   r   r   rZ   s
             r]   write_job_csvzLocalStorage.write_job_csv  s    kk&%(8399#rT[9\ 	B`aqV(KAMMO B

@AAaB.@AB	B 	B A		B 	Bs   =B%B	BBB#rU  c               r     | j                   j                  t        g| }|r|j                  dd       |S r   )r   rN  COMPANYr   )r   rO  r   rh   s       r]   _companyzLocalStorage._company  s5    DIIw//GGD4G0r_   c                    | j                   |ddi|z  }|j                         sg S |j                  dd      5 }t        j                  |      D cg c]  }t        |       c}cd d d        S c c}w # 1 sw Y   y xY w)NrO  FrQ   r   r   )rd  r   r   r   r   r   )r   rs   subdirrh   r   r   s         r]   read_company_csvzLocalStorage.read_company_csv  st    DMM60%08;xxzIVVBV1 	8Q%(^^A%67DG7	8 	87	8 	8s   A6A1%A61A66A?c                >    t         | j                  | |z  ||       y r   )r   rd  )r   rs   r   r   rf  s        r]   append_company_csvzLocalStorage.append_company_csv  s    =4==&)H4fcBr_   c                F    | j                   | |z  j                  ddd      5 }t        j                  ||d      }|j	                          |D ]5  }|j                  |D ci c]  }||j                  |      xs d c}       7 	 d d d        y c c}w # 1 sw Y   y xY wr  )rd  r   r   r   r   r   r   )	r   rs   r   r  rf  r   r   r   rZ   s	            r]   write_company_csvzLocalStorage.write_company_csv  s    dmmV$x/55c2PW5X 	B\]qV(KAMMO B

@AAaB.@AB	B 	B A		B 	Bs   =B"B?	BBB c                ^     | j                   | |z  }|j                  |       t        |      S r   )rd  r   rq   )r   rs   r   rf  rh   s        r]   put_company_filezLocalStorage.put_company_file	  s,    DMM6"X-	d1vr_   c                p     | j                   |ddi|z  }|j                         r|j                         S d S NrO  F)rd  r   r   )r   rs   rf  rh   s       r]   get_company_filezLocalStorage.get_company_file  s5    DMM60%08;!"q||~55r_   r   )r   rq   r   rq   r   dict[str, str] | None)r   rq   returnzPath | Noner   rq   rr  
str | Nonerr  
list[dict]r   rq   rr  rq   )r   rq   rr  r   r   rq   rr  z	list[Doc]r   rq   rr   rq   rr  ztuple[Doc, bytes] | Noner   rq   rs   rq   r   bytesrr  rq   r   rq   r   r   rr  Noner   rq   rr  	list[str]r   rq   rr  rv  r   rq   rr  list[tuple[str, str]])r   rq   r  rv  rr  r}  r   rq   r+  rq   r   r   rr  boolr   rq   rr  tuple[str, str]rr  rI  T)r   rq   rO  r  rr  r   r   rq   rs   rq   rr  bytes | Noner   rq   rs   rq   rr  rv  
r   rq   rs   rq   r   r  r   r   rr  r}  
r   rq   rs   rq   r   r  r  rv  rr  r}  )rO  r  rr  r   rx   rs   rq   rr  rv  rs   rq   r   r  r   r   rr  r}  rs   rq   r   r  r  rv  rr  r}  rs   rq   r   r{  rr  rq   rs   rq   rr  r  )-rt   ru   rv   r   r   r   r   r   rO   r   r   r   r  r  r  r  r  r  r  r  r"  r&  r-  r2  r4  r8  r:  r>  r@  rC  propertyrL  rP  rR  rV  r[  r]  r_  ra  rd  rg  ri  rk  rm  rp  rx   r_   r]   r   r      s    %
"%,"	

\8

8D(
(	
E8W8X Q Q	
6X
8GB /3 8CB
6r_   r   c                     e Zd ZdZdZd4d5dZd6d7dZd8d9dZd8d:dZd;dZ	d<d	Z
d=d
Zd4d>dZd?dZd@dZdAdZdBdZdCdZdDdZdEdZdFdZdGdZdHdZdIdZdDdZdJdZdKdZdEdZdGdZdLdZdHdZdDdZdEdZ dGd Z!dEd!Z"dGd"Z#dMd#Z$e%dNd$       Z&dOdPd&Z'dDd'Z(dQd(Z)dFd)Z*dRd*Z+dSd+Z,dTd,Z-d%d-dUd.Z.dVdWd/Z/dVdXd0Z0dVdYd1Z1dVdZd2Z2dVd[d3Z3y)\DriveStoragezUGoogle Drive via service account. Folder IDs cached per job for the process lifetime.z"application/vnd.google-apps.folderNc                $   |xs i | _         ddlm} ddlm} |j
                  j                  |dg      } |dd|d	      | _        || _        |j                  d
d      j                  d      D cg c]  }|s|	 c}| _        i | _        y c c}w )Nr   )service_account)buildz%https://www.googleapis.com/auth/drive)scopesdrivev3F)credentialscache_discoveryrG  rH  )r   google.oauth2r  googleapiclient.discoveryr  Credentialsfrom_service_account_filesvcr   rJ  rT   r   _cache)	r   sa_jsonjobs_root_idr   r   r  r  credsr   s	            r]   r   zDriveStorage.__init__  s    }"13++EEDE F 
 $E5Q 	#*??4#=#C#CC#HNaAN13 Os   1B9Bc                    g d }}	 | j                   j                         j                  |d| |ddd      j                         }||j	                  dg       z  }|j	                  d      }|s|S k)NTznextPageToken,   )qr   	pageTokensupportsAllDrivesincludeItemsFromAllDrivespageSizefilesnextPageToken)r  r  listexecuter   )r   r  r   rX   tokr   s         r]   _qzDriveStorage._q)  s    tS %%nVH5"&$QT &  gi  155"%%C%%(C
 r_   c                Z    d| d}|r|d| j                    dz  }| j                  |      S )N'z' in parents and trashed=falsez and mimeType=')FOLDERr  )r   r/  folders_onlyr  s       r]   	_childrenzDriveStorage._children5  s9    x56?4;;-q11Awwqzr_   c                    | j                  |      D ]  }|d   |k(  s|d   c S  |sy | j                  j                         j                  || j                  |gddd      j                         }|d   S )Nr   r   )r   mimeTyper   T)bodyr   r  )r  r  r  rO  r  r  )r   r/  r   rO  r   r   s         r]   _child_namedzDriveStorage._child_named;  s    ' 	AyD w	 HHNN##DKKVHM4 $ 
 ') 	
 wr_   c                   t        t        j                              | j                  j	                  j                               j                         dfd}| j                  | j                  d      D ]6  }| j                  |d   d      D ]  } ||d         s|d   |d   fc c S  8 | j                  | j                  d      D ]  } ||d         s|d   |d   fc S  y )Nr   c                N    r| j                        S | j                         v S r   )re   rW   )r   r   r   numerics    r]   r,  z*DriveStorage._find_job_folder.<locals>.hitK  s$    .54??6*N3$**,;NNr_   Tr  r   )r   rq   rr  r  )r  r   r   r   r   rW   r  r   )r   r   r,  stager
   r   r  s    `   @@r]   _find_job_folderzDriveStorage._find_job_folderG  s    w}}V,-llv||~v6<<>	O^^DIID^A 	2E~~eDk~E 2s6{#t9c&k112	2 >>$))$>? 	.C3v;4y#f+--	. r_   c           	     \   || j                   v r| j                   |   S | j                  |      }|st        |      |\  }}| j                  D ]  }| j	                  ||d      } |d   ||| j	                  |t
        d      | j	                  |t        d      d}|| j                   |<   |S )NTrU  r   )r
   job_namesignonr   signed)r  r  r   r   r  r   r   )r   r   foundcurr   rY   idss          r]   _idszDriveStorage._idsV  s    T[[ ;;v&&%%f-#F++	TLL 	<D##Cd#;C	< 8%%c4%=''VD'A

 "F
r_   c                    ddl m} t        j                         } ||| j                  j                         j                  |d            }d}|s|j                         \  }}|s|j                         S )Nr   )MediaIoBaseDownloadT)fileIdr  F)	googleapiclient.httpr  ioBytesIOr  r  	get_media
next_chunkgetvalue)r   file_idr  bufdldoner[   s          r]   	_downloadzDriveStorage._downloadg  s`    <jjl dhhnn&6&@&@cg&@&himmoGAt ||~r_   c                V   ddl m}  |t        j                  |      |d      }|r@| j                  j                         j                  ||dd      j                         }|d   S | j                  j                         j                  ||gd|dd	      j                         }|d   S )
Nr   )MediaIoBaseUploadF)mimetype	resumabler   T)r  
media_bodyr   r  )r   r   )r  r  r   r  )	r  r  r  r  r  r  r*  r  rO  )	r   r/  r   r   mimer  r  mediar   s	            r]   _uploadzDriveStorage._uploadp  s    :!"**T"2TUS ''w5QUim'nvvxA
 w  ''"x8USWko ( gi  wr_   c                J    	 | j                  |      d   S # t        $ r Y y w xY w)Nr  )r  r   r%  s     r]   r   zDriveStorage.find_job|  s-    	99V$Z00  		s    	""c           
        d| j                   v r| j                   d   d   S g t               }}| j                  g| j                  | j                  d      D cg c]  }|d   	 c}z   }|D ]  }| j                  |d      D ]  }|d   |v s|d   j	                  d      r|d   }| j
                  D ]  }| j                  ||d	      }|r n |sP|j                  |d          |j                  | j                  |d         |d   t        |d         d
         |D 	cg c]
  }	|	d   s	|	 }
}	d|
i| j                   d<   |
S c c}w c c}	w )u   Same question as the local backend, cached for the process — it is a folder walk.

        Only jobs holding the sign-on subpath count, so a stage folder full of finished work costs
        one listing and nothing else.
        _jobsr  Tr  r   r   r[   FrU  r   r   )r  r   r   r  re   r   r  r   rk   r   r   )r   rX   r   r   groupsr/  r
   r  rY   r   r  s              r]   r   zDriveStorage.list_jobs  sp    dkk!;;w'//T))		X\1]^A$^^ 	@F~~f4~@ @v;$&#f+*@*@*E$i LL D++Ce+DC V%

4==V#=s6{%0V%=? @@	@ +a!E(++ &~G#  _ ,s   E#
E.Ec                    t         j                  |      }|r|j                  d      S |j                         }| j                  j                         D ]  \  }}|j                         |v s|c S  yr   r   r   s         r]   r   zDriveStorage._key_for  sg    MM+&771:!LL&&( 	DAqwwyC	 r_   c                    | j                  |      }| j                  |d         D cg c]'  }|d   j                         j                  d      s&|) }}t	        d |D        d       S c c}w )Nr   r   r   c           	   3  l   K   | ],  }t        t        |d          |d    t        |d                 . ywr   N)rp   r   r   r   s     r]   r   z)DriveStorage.list_docs.<locals>.<genexpr>  s0     \QRs71V9-qy&6:KL\s   24c                6    | j                   j                         S r   r   r   s    r]   r   z(DriveStorage.list_docs.<locals>.<lambda>  s    AJJ$4$4$6 r_   r   )r  r  rW   r   r   )r   r   r  r   r  s        r]   r   zDriveStorage.list_docs  sh    ii NN3v;7^q1V9??;L;U;UV\;]^^\V[\68 	8 _s   'A+A+c           	     $   | j                  |      }| j                  |d         D ]h  }|d   j                         j                  d      s&t	        |d         |k(  s8t        ||d   t        |d               | j                  |d         fc S  y )Nr   r   r   r   )r  r  rW   r   r   rp   r   r  )r   r   rr   r  r   s        r]   r   zDriveStorage.get_doc  s    iiF, 	XAy ))&1gai6HD6P46F1V9,=>qQUw@WWW	X r_   c                \    | j                  |      }| j                  |d   ||d      }d| S )Nr  r   drive:)r  r  )r   r   rs   r   r  fids         r]   r   zDriveStorage.put_signed  s5    iill3x=(D:KLu~r_   c                0   | j                  |      }| j                  |d   t              }t        j                         }t        j                  |t              }|r`|j                  | j                  |      j                  d             |j                         j                  d      s"|j                  d       n|j                          |j                  |       | j                  |d   t        |j                         j!                  d      d|       y )Nr  r   r   
r   r  )r  r  r   r  StringIOr   r   r   writer  decoder  r   r   r   r  encode)r   r   r   r  r   r  r   s          r]   r  zDriveStorage.append_register  s    ii$$S]H=kkmNN3?;IIdnnX.55g>?<<>**40		$MMO	

3S]Hclln.C.CG.Ljbjkr_   c                   | j                  |      }| j                  |d   t              }|sg S | j                  |      j	                  d      j                         D cg c]#  }|j                         s|j                         % c}S c c}w Nr  r   )r  r  r  r  r  rd   rV   )r   r   r  r  r  s        r]   r  zDriveStorage.get_crew  sq    iiHt4I#'>>##6#=#=g#F#Q#Q#SaaWXW^W^W`	aaas   B
5B
c                "   | j                  |      }| j                  |d   t              }|sg S t        j                  t        j                  | j                  |      j                  d                  D cg c]  }t        |       c}S c c}w r  )
r  r  r   r   r   r  r  r  r  r   r   r   r  r  r   s        r]   r  zDriveStorage.list_register  sm    iiHx8I!$DNN3<O<V<VW^<_0`!abAQbbb   7Bc                r    | j                  |      }d|vr| j                  |d   t        d      |d<   |d   S )Ntake5r  TrU  )r  r  r  )r   r   r  s      r]   	_take5_idzDriveStorage._take5_id  sA    ii#,,S]E$,OCL7|r_   c                    | j                  | j                  |      t              }|r-t        | j	                  |      j                  d            }|r|S t        S Nr   )r  r  r  rn   r  r  r  )r   r   r  rB   s       r]   r  zDriveStorage.get_hazards  sL    v 6@s 3 : :7 CDC
r_   c                N    d| j                  | j                  |      ||d       S )Nr  r   )r  r  )r   r   rs   r   s       r]   r  zDriveStorage.put_take5  s)    T^^F%;XtM^_`aar_   c                    | j                  | j                  |      t              }|sg d fS t        j                  t        j                  | j                  |      j                  d                  D cg c]  }t        |       c}|fS c c}w r  )
r  r  r  r   r   r  r  r  r  r   r   r   r  r   s       r]   r  zDriveStorage._read_take5  sn    v 6Gt8O!$DNN3<O<V<VW^<_0`!abAQbdgggbs   4Bc                   t        j                         }t        j                  |t        d      }|j                          |D ]6  }|j                  t        D ci c]  }||j                  |d       c}       8 | j                  | j                  |      t        |j                         j                  d      d|       y c c}w Nr   r   rQ   r   r   r  )r  r  r   r   r  r   r   r   r  r  r  r  r  )r   r   r  r  r  r   r   rZ   s           r]   r  zDriveStorage._write_take5  s    kkmNN3<hO	 	@AJJ>A155B<>?	@T^^F+^S\\^=R=RSZ=[]gqtu ?s   C
c                t    | j                  |      \  }}|j                  |       | j                  |||       y r   r!  )r   r   r   r  r  s        r]   r"  zDriveStorage.append_take5  s4    $$V,	cC&$,r_   c                *    | j                  |      d   S )Nr   r$  r%  s     r]   r&  zDriveStorage.list_take5  s    '**r_   c                    | j                  |      \  }}d}|D ]*  }|j                  d      |k(  s|j                  |       d}, |r| j                  |||       |S r(  r)  )r   r   r+  r   r  r  r,  r   s           r]   r-  zDriveStorage.finish_take5  sg    $$V,	c 	AuuT{h& 	 fdC0
r_   c                    | j                  |      }d|vrH|d   }| j                  d d D ]  }| j                  ||d      } | j                  |t        d      |d<   |d   S )N	incidentsr
   r   TrU  )r  r   r  r0  )r   r   r  r  rY   s        r]   _incidents_idzDriveStorage._incidents_id  s{    iic!e*CSb) @''T$'?@#00i0MC;r_   c                    |j                         j                  d      rdnd}d| j                  | j                  |      |||       S )Nr   r   r   r  )rW   r   r  r
  )r   r   rs   r   r  s        r]   r4  zDriveStorage.put_incident_file  sG    $,NN$4$=$=f$E <T%7%7%?4QUVWXXr_   c           
     v   | j                  |      }| j                  |t              }t        j                         }t        j                  |t        d      }|r`|j                  | j                  |      j                  d             |j                         j                  d      s"|j                  d       n|j                          |j                  t        D ci c]  }||j                  |d       c}       | j!                  |t        |j                         j#                  d      d|       y c c}w )Nr   r   r   r  rQ   r   r  )r
  r  r6  r  r  r   r   r7  r  r  r  r  r   r   r   r   r  r  )r   r   r   folderr   r  r   rZ   s           r]   r8  zDriveStorage.append_incident  s    ##F+$$V->?kkmNN3?RIIdnnX.55g>?<<>**40		$MMO	

?!Aswwq"~%?@V.0E0Eg0NPZdlm @s   D6c                   | j                  | j                  |      t              }|sg S t        j                  t        j                  | j                  |      j                  d                  D cg c]  }t        |       c}S c c}w r  )
r  r
  r6  r   r   r  r  r  r  r   r  s       r]   r:  zDriveStorage.list_incidents'  sg     2 26 :<MNI!$DNN3<O<V<VW^<_0`!abAQbbbs   2Bc           
     D   | j                  |      }| j                  |d   t              }g }t        }|rt	        j
                  t        j                  | j                  |      j                  d                  }|D cg c]  }t        |       }}t        |j                  xs g       }	t        D 
cg c]	  }
|
|	vs|
 }}
|	r|	|z   nt        }|j                  |       t        j                         }t	        j                  ||d      }|j                          |D ]5  }|j!                  |D ci c]  }||j#                  |      xs d c}       7 | j%                  |d   t        |j'                         j)                  d      d|       y c c}w c c}
w c c}w )Nr  r   r   r   rQ   r   r  )r  r  r<  r=  r   r   r  r  r  r  r   r  r   rk   r   r   r   r   r  r  r  )r   r   r   r  r   r  r   rdrr   r  rm   r   r  r   rZ   s                  r]   r>  zDriveStorage.append_attendance.  sV    ii$$S]4GH"..T^^H-E-L-LW-U!VWC%()DG)D)s~~+,C"3DQq|qDGD&)S7]/@FCkkmNN36I	 	>AJJV<AEE!HN*<=	>S]$79N9Nw9WYcmuv *D =s   ?F4	F>F2F
c                "   | j                  |      }| j                  |d   t              }|sg S t        j                  t        j                  | j                  |      j                  d                  D cg c]  }t        |       c}S c c}w r  )
r  r  r<  r   r   r  r  r  r  r   r  s        r]   r@  zDriveStorage.list_attendanceD  sn    iiH/BCI!$DNN3<O<V<VW^<_0`!abAQbbbr  c                    | j                  |      }| j                  |d   t              }|r)t        | j	                  |      j                  d            S dS )Nr  r   rc   )r  r  rB  ri   r  r  )r   r   r  r  s       r]   rC  zDriveStorage.get_foremanK  sL    iiH|<EH}T^^C077@AVhVr_   c                ,    t        | j                        S r   )rI  r   rK  s    r]   rL  zDriveStorage.signon_partsQ  s    T\\""r_   Tc                    | j                  |      }dj                  |      }||v r||   S |d   }|D ]  }| j                  |||      }|r y  |||<   |S )Nrb   r
   rU  )r  joinr  )r   r   r   rO  r  r   r  rY   s           r]   	_under_idzDriveStorage._under_idU  sr    iihhuo#:s8O%j 	D##Cf#=C	 C
r_   c           	         | j                  ||      }| j                  ||      }d| j                  |||t        |      |       S Nr  r  )r  r  r  r   )r   r   r   rs   r   r  r   s          r]   rR  zDriveStorage.put_job_filec  sK    .$$VX6VXtXh=OYabcddr_   c                    | j                  ||d      }|r| j                  ||      nd }|r| j                  |      S d S rT  )r  r  r  )r   r   r   rs   r  r  s         r]   rV  zDriveStorage.get_job_fileh  sB    e<5;d1&)t~~c"3t3r_   c                t    | j                  ||d      }|r!t        d | j                  |      D              S g S )NFrU  c              3  &   K   | ]	  }|d      ywr  rx   r   s     r]   r   z.DriveStorage.list_job_files.<locals>.<genexpr>o  s     @Aai@s   )r  r   r  )r   r   r   r  s       r]   r[  zDriveStorage.list_job_filesm  s8    e<DJv@)?@@RPRRr_   c                "   | j                  ||d      }|r| j                  ||      nd }|sg S t        j                  t	        j
                  | j                  |      j                  d                  D cg c]  }t        |       c}S c c}w )NFrU  r   )	r  r  r   r   r  r  r  r  r   )r   r   r   rs   r  r  r   s          r]   r]  zDriveStorage.read_job_csvq  ss    e<5;d1I!$DNN3<O<V<VW^<_0`!abAQbbbr  c                v    | j                  |||      }|j                  |       | j                  |||||       y r   )r]  rk   ra  )r   r   r   rs   r   r   r  s          r]   r_  zDriveStorage.append_job_csvx  s8      9C65(FDAr_   c           
        | j                  ||      }| j                  ||      }t        j                         }t	        j
                  ||d      }	|	j                          |D ]5  }
|	j                  |D ci c]  }||
j                  |      xs d c}       7 | j                  |||j                         j                  d      d|       y c c}w r  )r  r  r  r  r   r   r   r   r   r  r  r  )r   r   r   rs   r   r  r  r   r  r   r   rZ   s               r]   ra  zDriveStorage.write_job_csv}  s    .$$VX6kkmNN36I	 	>AJJV<AEE!HN*<=	>VXs||~'<'<W'Ez[cd =s   5C
rU  c                  ddj                  |      z   }|| j                  v r| j                  |   d   S | j                  | j                  t        |      }|D ]  }|s y | j                  |||      } |sy d|i| j                  |<   |S )Nz	_company|rb   r   rU  )r  r  r  r   rc  )r   rO  r   r   r  rY   s         r]   _company_idzDriveStorage._company_id  s    CHHUO+$++;;s#D))		76B 	>D##Cf#=C	>  #;C
r_   c                    | j                   |ddi}|r| j                  ||      nd }|sg S t        j                  t	        j
                  | j                  |      j                  d                  D cg c]  }t        |       c}S c c}w )NrO  Fr   )	r   r  r   r   r  r  r  r  r   )r   rs   rf  r  r  r   s         r]   rg  zDriveStorage.read_company_csv  sv    !!!68%85;d1I!$DNN3<O<V<VW^<_0`!abAQbbbs   5B
c                r    | j                  ||      }|j                  |       | j                  ||||       y r   )rg  rk   rk  )r   rs   r   r   rf  r  s         r]   ri  zDriveStorage.append_company_csv  s4    $$Xv6Cxv>r_   c           
         | j                   | }| j                  ||      }t        j                         }t	        j
                  ||d      }|j                          |D ]5  }	|j                  |D 
ci c]  }
|
|	j                  |
      xs d c}
       7 | j                  |||j                         j                  d      d|       y c c}
w r  )r   r  r  r  r   r   r   r   r   r  r  r  )r   rs   r   r  rf  r  r   r  r   r   rZ   s              r]   rk  zDriveStorage.write_company_csv  s    !!!6*$$VX6kkmNN36I	 	>AJJV<AEE!HN*<=	>VXs||~'<'<W'Ez[cd =s   2C
c           	          | j                   | }| j                  ||      }d| j                  |||t        |      |       S r  )r   r  r  r   )r   rs   r   rf  r  r   s         r]   rm  zDriveStorage.put_company_file  sM    !!!6*$$VX6VXtXh=OYabcddr_   c                |     | j                   |ddi}|r| j                  ||      nd }|r| j                  |      S d S ro  )r   r  r  )r   rs   rf  r  r  s        r]   rp  zDriveStorage.get_company_file  sE    !!!68%85;d1&)t~~c"3t3r_   r   )r  rq   r  rq   r   rq   r   rq  )zfiles(id,name,mimeType))r  rq   )F)r/  rq   )r/  rq   r   rq   rr  rt  )r   rq   rr  ztuple[str, str] | None)r   rq   rr  dict[str, str])r  rq   rr  r{  )r/  rq   r   rq   r   r{  r  rq   r  rt  rr  rq   rs  ru  rw  rx  ry  rz  r|  r~  r  )r   rq   rr  rq   r  )r   rq   rr  ztuple[list[dict], str | None])r   rq   r  rv  r  rt  rr  r}  r  r  r  r  )r   rq   rO  r  rr  rt  r  r  r  r  )rO  r  rr  rt  r  r  r  r  r  r  )4rt   ru   rv   __doc__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
  r4  r8  r:  r>  r@  rC  r  rL  r  rR  rV  r[  r]  r_  ra  r   rg  ri  rk  rm  rp  rx   r_   r]   r  r    s   _1F4

"	88
lbcbhv-
+	 Yncw,cW # #e
4
ScB
e 26 c?
ee
4r_   r  c                 .   ddl m}   |         t        j                  dd      }t	        t        j                  dd            }t        j                  d      }|rt        |||      S t        t        j                  d   t        j                  d	   ||      S )
Nr   )load_dotenvSIGNON_SUBPATHz05. Safety & Compliance/Sign-OnJOB_ALIASESrQ   LOCAL_JOBS_ROOTGOOGLE_SERVICE_ACCOUNT_JSONJOBS_ROOT_FOLDER_ID)dotenvr)  osgetenvr^   r   r  environ)r)  r}   r   locals       r]   from_envr4    s    "M
))$&G
HCBIImR89GII'(EE300


01


()	 r_   )rG   rq   rr  r&  )rG   rq   rr  r  )rG   rq   rr  r  )rs   rq   rr  rq   )r   rp   r   rq   r   r   rr  rq   rw  )r   r   r   r  r   r   rr  r}  )Ar'  
__future__r   r   r  r0  r~   dataclassesr   r   pathlibr   r   r   r   r  r   r  r  r  r  r  r0  r6  r7  INCIDENT_KINDSr<  r=  TM_PARTSTM_REGISTER	TM_HEADERMATERIALS_REGISTERMATERIALS_DIRMATERIALS_HEADERMATERIAL_STATUSDIARY_PARTSBOARD_REGISTERBOARD_HEADERDIARY_NOTESDIARY_NOTES_HEADERROSTERROSTER_HEADER	FLEET_DIRPLANT_REGISTERDEFECTS_REGISTERPLANT_HEADERrc  rB  r^   ri   rn   compiler   Ir|   rp   r   r   r   r   r   r   r   r  r4  rx   r_   r]   <module>rM     s   # 
 	 	 	 !  	Y 	%
F  	+ I?MnNP 0 C 
 1^	
 . ^ *yP\] 4 &O  ; 
 
F 	%  8
 
 "**]
#
"**/
6   ?#
H
	8F[6 [6B	^4 ^4Br_   