SjM dZddlZddlZddlZddlZddlZddlZddlmZm Z m Z ddl m Z ddl Z ddlZddlmZmZedej&dZej&dZej&d ZdZe d Zd Zd Zej6d Zdej:vZdZdZ de!de!de!fdZ"de!de#dzfdZ$de!de!de!de#de%f dZ&de!ddfdZ'de!de(e#fdZ)de!fdZ*du Outlook ↔ vault.db sync. Sincronizza calendario e task da Microsoft Graph a vault.db (SQLite locale). Usage: venv/bin/python3 outlook_sync.py [--dry-run] N)datetimedate timedelta)Path) load_dotenvset_keyz/mnt/ssd/adrian/.envOUTLOOK_CLIENT_IDOUTLOOK_CLIENT_SECRETOUTLOOK_REFRESH_TOKENz"/mnt/ssd/data/adrian-ops/adrian.dbz=https://login.microsoftonline.com/consumers/oauth2/v2.0/tokenz https://graph.microsoft.com/v1.0 Europe/Romez --dry-runc td|y)Nz[outlook_sync] )print)msgs >/mnt/ssd/data/Dropbox/adrian/vault-secondbrain/outlook_sync.pylogr#s OC5 !"cbtjt}tj|_|SN)sqlite3connectVAULT_DBRow row_factory)conns r_dbr)s! ??8 $D{{D Krprefix outlook_idreturncxtj|jjdd}|d|S)N-)hashlibsha256encode hexdigest)rrhs r_item_idr'/s9z((*+557?szz$U3H 5D||=zJSSUH AD(T[C\] P ix 0 KKMJJL Mrc~t}|jd|f|j|jy)NzDELETE FROM items WHERE id=?)rr,r:r.)r(rs r vault_deleter@Qs, 5DLL/'<KKMJJLrct}|jd|fj}|jg}|D]=}t |}t j |dxsd|d<|j|?|S)Nz SELECT * FROM items WHERE type=?r*r+)rr,fetchallr.r/r0r1append)r5rrowsresultr2r3s r vault_queryrFXsy 5D <<:YL I R R TDJJL F IJJqy0D1&  a Mrctjtttdddd}|j |j }d|vr |dtk7rttd|d|dS)N refresh_tokenz2Calendars.ReadWrite Tasks.ReadWrite offline_access) client_idrH grant_typescope)datatimeoutr access_token) httpxpost TOKEN_URL CLIENT_ID REFRESH_TOKENraise_for_statusr0rENV_FILE)rrMs rget_access_tokenrXfsr 9&%E $   A  668D$4#8M#I143HI  rtokenpathparamsctjt|dd|i|d}|j|j S)N AuthorizationBearer )headersr[rN)rPget GRAPH_URLrUr0)rYrZr[rWs r graph_getrctsH YKv&*geW,=> -A 668Orctjt|d|dd|d}|j|j SNr^zapplication/json)r]z Content-Typer_)r`r0rN)rPrQrbrUr0rYrZr6rWs r graph_postrg|sI i['/6ug->Pbcb *A 668Orcrtjt|d|dd|d}|jyre)rPpatchrbrUrfs r graph_patchrjs> yk$(07w.?Qcdr +Arc tjt|dd|id}|jdvS#t$r}t d|d|Yd}~yd}~wwxYw) Nr]r^r_)r`rN)iz [ERR] graph_delete z: F)rPdeleterb status_code Exceptionr)rYrZrWes r graph_deleterqsj LLI;tf-"1WUG3D!Er S}} **  #D6A3 /0s25 AAAdt_strc,|syd|vrtj|jdd}|jtj j |}|jt}|jd|jdfS|dddfS)NNNTZz+00:00%Y-%m-%d%H:%M ) r fromisoformatreplacetzinfo_pytzutclocalize astimezone _LOCAL_TZstrftime)rrdtdt_locals rparse_datetimers  f}  # #FNN3$A B 99 ##B'B==+  ,h.?.?.HHH #2; rtextc|syddl}tjdd|}d}||k7r|}|j|}||k7rtjdd|j }|r|SdS)Nr<[^>]+>z[\xa0]+ )html_resubunescapestrip)r_htmlcleanedprevs r clean_htmlrso ggj"d+G D '/..) '/ggj#w/557G7'4'rweeklybiweeklymonthlyannualdaily)rrabsoluteMonthlyrabsoluteYearlyrrrrrrrr)rrrrrc td|} tjj} ||||||||| | || d| d}t | d||S)Neventoutlook)titler start_timeend_timelocation descriptioncategoryrrule rrule_until is_all_dayroutlook_last_modifiedsource updated_at)r'rutcnow isoformatr>)oidrdate_strrrrrrrrrrr(nowr*s r _upsert_eventrsbw$G //  % % 'C PX[h{*4I3  D % 66rc|dd|jdxsddd}|jds"|jdsn|jd s]d |d <|d d dd|d<tjt|d dt dz}|j dd dd|d<n|jdxsd}|jd xsd}||krIt |ddt |dd}}tddd||t dz}|j d}|d d|ddd|d<|d d|ddd|d<|jdr d |di|d<|jd!rtj|d!d"\}} |rtjt|d d} || d#} |d$k(rgd%} | | jg| d&<n8|d'k(r| j| d(<n#|d)k(r| j| d(<| j| d*<|jd+rd,t|d t|d+d-} nd.t|d d/} | | d0|d1<|S)2Nrrrr) contentTypecontent)subjectr6rrrTisAllDayr T00:00:00UTCdateTimetimeZonestartrwrdaysendz00:00ri)hoursrxruz:00r r displayNamerrt)typeintervalr)mondaytuesday wednesdaythursdayfridaysaturdaysunday daysOfWeekr dayOfMonthrmonthrendDate)r startDaternoEnd)rr)patternrange recurrence) rarstrptimestrrrintRRULE_TO_OUTLOOKweekdaydayr)r*r6end_dtstart_tend_tr&mend_dt_tpat_typer event_dater day_names rec_ranges r_build_event_bodyrs= &488M3J3PbQD xx dhh|&rorjr@) rYcreatedupdatedpre_sync_eventsrp local_onlylocal_modifiedractive_outlook_idscv_dataevrrrr_rrrrrr<r outlook_lmr= push_created push_updateditemrrEnew_oid del_counts r sync_calendarrsGg"'*O,PAfIMM,4O!PJP" V9== & fIMM, ' fIMM1 2 fIl #ai0G&H H N JJLE#&51!7*-)"445Z@4G kk'2&& 66&>^ + hs#y!5%5-bkooj.I.hRPW[__]cegMhi*$RY]]:%>%["U)--PVXZB[\ 866*b)--m<D !3!7!7 !BC VVL"- ,6:a=&&(K  '3!78H (x8X>bsAS@TTWX`Waabchbij k Hq! +G Hq! +G VVJ. @BG]@^RVV2B7-H-H-J)*"*//"3"="="?,T$Z$v,B! )!%%-!%%.9IJK@& @ L  'f ag7GH I A L  @ Q|_,=>@QRS@T U)1):)D)D)FA% & dWd6lA > A L %aeeFm_AaeeGn5EF G @| "<. ,{ ST  # Dv,""<0Cs"44T$Z(Q    ,YK8 9 G AQ~ @ 'g'7s1#> ? ? @ @ 'g'7s1#> ? ? @sBTTATCT B U U& U  U V VVc tt|d}dx}}t}|jdgD]}|d}|jdd}t|d|dd d i}|jdgD]T} | jd d k(r| d} | jd xsd} | jdd} ddddj| d} d}| jdr| djdd}| djdd} tj|j dj dd}|dk7rtj|ntj}|j|jtjd}|jd}| jdijdxsd}|r)tjd d|j!xsd}|j#d!vr|j#nd}|j%| t'd"| }t)|}t*r)t-d#|rd$nd%d&| ||rdnd'z }||rd'ndz }tj.j1}| |d(| ||| |d)}t3|d"| |}||rd'ndz }||rdnd'z }Wt*sSt5d"}d}|D]1}|d*jd+} | s| |vst7|d|d'z }3|rt-d,|||fS#t$r |dd}YwxYw)-N/me/todo/listsrrrrr/me/todo/lists//tasksrdstatus completedrr importancenormalhighmediumlow)rrr  dueDateTimerrrrv.r rwryr6rr)tasks attivitàtodorrrz task: rpending)rrrprioritydue_daterrrr*rz Task cancellati da Outlook: )rcrrarrzrstripsplitr}timezoner~rrrrorrrrrr'r4rrrrr>rFr@)rY lists_datarrr lstlist_id list_name tasks_datataskrrrr'r(rrtz_strrsrc_tzrrr(r<rr*r= all_todosclosedrs r sync_tasksr6hsR5"23JGg#&5~~gr*.*d)GGM2. uy&G&RUW NN7B/) *Dxx![0t*CHHW%9)9E,9J &(5IMMjZbcHHxx &m,00R@m,00UC+!// c0B0H0H0Ma0PQB7=U^^F3EIIF,77}8UVB!{{:6H((62.229=EK!ggj"kBHHJRd ,5OO,=E[,[y(acH  " "3 'vs+G )Hh8xB'%QR1a/1a///#--/C{i$(!D "'65$?F Fq )G Fq )GS) * .*b '  Dv,""<0Cs"44T$Z(!     09 : G O!+%cr{H+sB$L%%L76L7c$t|d}d}|jdgD]=}|jds|jddjdvs8|d}n|s|jdr |ddd}|s td yd d d d }d}t dD]5}|d}|jds|jddk7r/t r#td|jd|dz }X|j|jddd }|d|d} |jdr|dddd| d<|jdr |ddd | d!< t |d"|d#| } | jd} | r>| |d<tjj|d$<t|dd|d!||dz }td%|d8|S#t$r+} td&|jdd'| Yd} ~ jd} ~ wwxYw)(NrrisOwnerrr)r#r$r1rrz) push_tasks: nessuna lista To Do trovatarrr )rrr r%r*rrr&u [DRY] CREATE task→Outlook: rrr'r)rrr(rr rr!rr)rrr6rrru Task→Outlook: z [ERR] push task "r) rcrarrrFrrgrrrr>ro) rYr,default_list_idr- priority_maprrrrr6rErrps r push_tasksr;s95"23JO~~gr* 779 #''-"<"B"B"DHf"f!$iO  z~~g6$W-a06  78"huELGF#> L 55 !%%/Y">   1!%%.1AB C qLG !%%aeeJ&A8L  zD 55 23J- /JXe"fD  55 '('7ODL >8I'PRVWF**T"C"%,"*//"3"="="?,T$ZfqA qLG $QwZL1 2->4 N > %aeeGn%5S< = = >sA8G H$ H  Hc*ttttgs t dt j dtr t dt dt}t dt dt|\}}t d|d|d t d t|\}}t d|d|d t d t|}|rt d|d ||z|z|z}t d |tr t dyy)Nz,Errore: credenziali Outlook mancanti in .envru&Modalità DRY RUN — nessuna modificazOttengo access token...zToken ottenuto.z'Sync calendario (prossimi 90 giorni)...u → rrzSync task (To Do)...uPush task →Outlook...z creatiz$Sync completato. Totale operazioni: u((DRY RUN — nessuna modifica applicata)) allrS CLIENT_SECRETrTrsysexitrrXrr6r;)rYeceutctutpctotals rmainrGs  =-8 9 :;   45!"  E12 5 !FB&IbT-.  FB&IbT-.!" U C  fSE !" GbL2 E .ug67 67r__main__r)NNFN)<__doc__r?osr0r"rrerrrrpathlibrrPpytzr}dotenvrrgetenvrSr>rTrVrrRrbr+rargvrrrrr'r/r4boolr>r@listrFrXrcrgrjrqtuplerrOUTLOOK_RRULE_MAPrrrrrr6r;rG__name__rrrWs  .. ' "# -.  12  12 & 5 6 K . ENN= )  !#  Scc  s td{ ##S$#$ 3 4:   #  STTcDTs#Td34 3 5tS4Z)?#@  (S (S4Z (%# %#  FK(, 715 7)D)T)XeesCxeTAcAeCHoAH*c*c*^8< zFr