From ff4ecf7d6f446ff7b0f8627904832986c5720543 Mon Sep 17 00:00:00 2001 From: Cyrille LOUARN Date: Sun, 8 Oct 2023 11:28:16 +0200 Subject: [PATCH] [1.9.21] - 3 lines tags supported, cleaner code, see changelog --- CHANGELOG.md | 10 + README.md | 7 +- src/usr/bin/tyto | 38 +- .../program/__pycache__/args.cpython-311.pyc | Bin 2602 -> 2602 bytes .../program/__pycache__/check.cpython-311.pyc | Bin 27806 -> 30358 bytes .../program/__pycache__/debug.cpython-311.pyc | Bin 3847 -> 3846 bytes .../__pycache__/domain.cpython-311.pyc | Bin 24793 -> 24791 bytes .../program/__pycache__/forms.cpython-311.pyc | Bin 8324 -> 8310 bytes .../program/__pycache__/help.cpython-311.pyc | Bin 435 -> 435 bytes .../program/__pycache__/langs.cpython-311.pyc | Bin 2857 -> 3014 bytes .../program/__pycache__/new.cpython-311.pyc | Bin 729 -> 729 bytes .../program/__pycache__/post.cpython-311.pyc | Bin 5943 -> 6072 bytes .../program/__pycache__/show.cpython-311.pyc | Bin 1173 -> 1173 bytes .../program/__pycache__/tools.cpython-311.pyc | Bin 5114 -> 6311 bytes .../program/__pycache__/tyto.cpython-311.pyc | Bin 1054 -> 1182 bytes .../__pycache__/userset.cpython-311.pyc | Bin 1016 -> 1016 bytes src/var/lib/tyto/program/args.py | 62 +- src/var/lib/tyto/program/check.py | 904 ++++++++--------- src/var/lib/tyto/program/debug.py | 79 +- src/var/lib/tyto/program/domain.py | 913 +++++++++--------- src/var/lib/tyto/program/forms.py | 256 ++--- src/var/lib/tyto/program/help.py | 2 +- src/var/lib/tyto/program/langs.py | 110 ++- src/var/lib/tyto/program/new.py | 16 +- src/var/lib/tyto/program/post.py | 247 ++--- src/var/lib/tyto/program/show.py | 30 +- src/var/lib/tyto/program/tools.py | 170 ++-- src/var/lib/tyto/program/tyto.py | 11 + src/var/lib/tyto/program/userset.py | 33 +- 29 files changed, 1502 insertions(+), 1386 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 929980e..84e5828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ Tyto - Littérateur # CURRENTLY IN DEV ! +## [1.9.21] +- new indentation (3 spaces) +- added 'raw:' marker +- (for wip process): +- - added html titles to post database +- - added html comments to post database (default: ';; a comment') +- - added val3 tag as html comment to content, and convert content to base64 +- - - added values to post database +- cleaner code + ## [1.9.20] - working on 'check' process - - updated 'logo:' process diff --git a/README.md b/README.md index 0f3e456..882618b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ tyto ## ToDo next (working on) - 'check' action processes -- create template post database +- - support for words tags (bolds...) +- - support lists, anchors +- - thinking about creating an auto top article menu from titles +- - stats for article words +- manage template post database +- - check valid database - Translate logs in english ! diff --git a/src/usr/bin/tyto b/src/usr/bin/tyto index 62062b9..01f12d5 100755 --- a/src/usr/bin/tyto +++ b/src/usr/bin/tyto @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Version: 1.9.20 -# Updated: 2023-10-06 1696580458 +# Version: 1.9.21 +# Updated: 2023-10-08 1696756865 # Tyto - Littérateur # Copyright (C) 2023 Cyrille Louarn @@ -48,27 +48,27 @@ import os # Error message # #---------------# def error_message(path): - print("! Installation error, unused:", path) - sys.exit(1) + print("! Installation error, unused:", path) + sys.exit(1) #======================================================# # A little checker to be sure, all files are installed # #------------------------------------------------------# def check_install(): - if not os.path.exists(libs): error_message(libs) - if not os.path.exists(trfs): error_message(trfs) - - for f in prog_files: - f = os.path.join(libs, f + ".py") - if not os.path.exists(f): - error_message(f) - - # Only default lang files - for f in lang_files: - f = os.path.join(trfs, f + ".py") - if not os.path.exists(f): - error_message(f) + if not os.path.exists(libs): error_message(libs) + if not os.path.exists(trfs): error_message(trfs) + + for f in prog_files: + f = os.path.join(libs, f + ".py") + if not os.path.exists(f): + error_message(f) + + # Only default lang files + for f in lang_files: + f = os.path.join(trfs, f + ".py") + if not os.path.exists(f): + error_message(f) @@ -77,8 +77,8 @@ def check_install(): #======# import sys if not __name__ == "__main__": - print("! Error: '%s' not '%s'"%(__name__, "__main__")) - sys.exit(1) + print("! Error: '%s' not '%s'"%(__name__, "__main__")) + sys.exit(1) # files list in /program/ prog_files = { diff --git a/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc index 27a7f6a2478de13da1e16d64d2fd6cb2c18cad03..553053a0a1274f83e006dfea09ed722f94850f1a 100644 GIT binary patch delta 497 zcmZ1_vPy(^IWI340}$|-Dx|h<trMc(iNpJ78PAt8ec zd!Q;NawJF!~_Ez{1yH)SA{})tfdo z?IN@66=vBBFf{o!$ICErU;r>e2_ZH{wGRw%LV}$U7(8%7iiJ_^0|T585oVP8z<^1B G0|5XH9He^y delta 497 zcmZ1_vPy(^IWI340}w25mPn1=$m`80BP=$>Vus@s>kc&#{BeUxbb=9t-Jv$Qgz>p4 zvI1o3A3uIP;1O(4zst(qQQ8#W5Wj$BLOKXG0NI--Fx_UXmsYsIB;TM4Bsx?lsNUrj znqW9Jd9LytjfuHaaxe0#T;Wyuz`)F`4<;It@AB~XcuWZH@tqrTMOOa;kA8zIAtAjB zJbDeT4Xz*9Va61J{Fe;!Bg5oZEFaA|`KOvpvAMu04@7raI9ohB5+_K_4O$2H088NY6VG_H@ByojF;sTSzQzqU< z-4@*j-MdUYjXEtl4LV2+zDB(ky#~F>b2v2AIXFKsaBy%oD18uNVCHR5Y7J}A>J6J3 zc9BWu3X{wQ7@GW=<7Jo_FaQ{#gb*8}>IVimA;HcF3?4Wk#lk4^fdNj42s6rlV8A56 GfdBxoo1VA; diff --git a/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc index 8af7c7ccc55a16cb14168d27a336499ee240c977..b52b8168337137d9a7595dcbb6b1d5b1106c28b0 100644 GIT binary patch literal 30358 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 delta 10360 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 aoThg1G|TWpj%I;mKUGDvcpCUf;Qs)GO-5G$ diff --git a/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc index f519fad91860d24dec57728b3c55bd32403c4cbe..c751f538f4148c0807124c0372ecdba8c28499f6 100644 GIT binary patch delta 296 zcmZpdYm?($&dbZi00d7>6jCiW@*d}^U(C$F(7z`{A1iO=4Oi~A!38w=ML z5b*&_h%m5ogPbdJgOg_hbC*TQWL|8*^K78*(3T@itgZuHnm43}a*j MIvzV&lm!eL09p}MxBvhE delta 297 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 bP2NvWsV(Xyg1P~9<8rG(-8+vz`YHEcn{BS0 delta 5561 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�~&9{=v^gytGpmDNb&-; zukAvw_m(+vb7g%+{XTWVqh+)8(ZlQ*g2hUu0e-Mh_T0*yy3# zGkCR8t)tsBcqsu-%8o~yPa`!*ZI3^s%hBbj7i;hSpI_TT(m&GAZnBQP6+6A97I&4? zn|L~E;^kiTazQ_Xcyb2%ayVH0@F4gfv{23hn#E|gj9N0W<_9f$!(Iz*&~H)Sazgsk zL(YvkciCdwS=w64%+nX7+Iv~D{#K2hk-`#jj(xp!aJl{I$kUsIy#(wf+-Ox!XYf!9 zzy6)AeSdiA0VBPFbh?ioYAe-lj!3=3y_9`w{sv($0(%j&7c1Vj-foT7MXdDp<$bsYJb%JAIui! z?-c#EFRAa%-&nd1EnSM9So*-yC)2B# m%4VvL1o_lPIDIbt^UP{?TyZGp2?_%W<9b8k{mq~LJ@Z$euCJ;9 diff --git a/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc index ca43d33e9edcb97395a46b45819b34786955d64a..9ef207c7f379489d83dba112f3b82d59a62c3eda 100644 GIT binary patch delta 1992 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 PYSiJ>b-heuW@7r^(RtOB diff --git a/src/var/lib/tyto/program/__pycache__/help.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/help.cpython-311.pyc index 10adcae716f2f1dcf0a6aac2dc6817a3d4eee52a..5090c9a545d2eba6f64647d3a0835443a0b2f597 100644 GIT binary patch delta 78 zcmdnYyqTGIIWI340}xCVQcRt_kynIKf|;XNv`6X+r{YCsr7O%z7hq_zC1Zk=@&^V+ LMs%Wx2WS8Q`qL6q delta 78 zcmdnYyqTGIIWI340}x!i&XhW9Bd-Xf1QUBNYY*2I4uy+MidUEvFTl`bOU48#r4I~@ LjOauW56}PrDuWXN diff --git a/src/var/lib/tyto/program/__pycache__/langs.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/langs.cpython-311.pyc index cb08c4b4d22f137a83292136beee7296de288557..6403d4d4654cf12e5fd9663edfd9995f01cb8219 100644 GIT binary patch delta 1381 zcmZWn&ube;6rRzpM$*`;L@P^jiIYmUY@s9-QM1C5-Ks7a0xk3sx5SXtsNKbuk?mwx z{gEO^+tvqB3YEJyF%*FdRiY3A0$=h6l%BO^ON~H~ivqnVhkz-x^ot0+o8h}xQbZev+%I=)ao(Xx5vtMj2?F0;O@ z%>=XSc|~2%*>5?UGcIjt)70 zIm|rpkB-`OZ11D$LM<_2(zr$A9fW!DQ1Iw-+cQ>?tMhx;O-~fIr*3`rpvv>O$j(=J z1|kD5gD&|o<^>rXQ+MY!GV&68t{(X*NPi5bEdVg`cHZA2ZheJ~qmGS(Pzda~suzEb z{Sq@rFPTEz65_ht)05j>7^}?I?6q68@}XLoMj-TZNLf3Z%?z_b;ZE~QE-ka2RiuzhFe z4vQe}NxAsQRZo~SWzp0GlQPs2&uzzcVtTecGG3j36m3jM=7^-H+tl0Oyv7aZv*IKi zr?SJFJZt-=Q)90U-U)r*U^P(&K?cYAdb;}l?;e+-;u|n+5kN=J2^#X1um3Urra3NI zg#&;Y_NmVFhvvi%3w0cpAb delta 1273 zcmZWoO=ufO7@gT2tu$HvZM2q~*mbN#jw7Y9l1f!=2r4bc*u@lreQ4=HDBg|hRJO~m zn&6_MJ@g<-p>kytK@g}=wKAn3@Fj=U4QZPB?8_ALrXJ_Z}{q4+~ zH{U)PJ@C8!aJkMPc;_q_@}gmi@kZTi?j2Eu8$0pZR9zxeZoXea_Ze2-#aCquqg`jF!B!kycyW zb}_-dhdsrwxleO4)I?$GUjZ1XD7+#`yNKhZHlaT(TD|9*v3QneA2L@W|%kVsSX=0Es{y7KaW zuoqfmaJbCN7z@P|`6wrWuQ5Iv1vo(32(x_vE$6zLN$NX#GM(C5*WQKDB1}CE(Bmv! zFs^o_QA@gFN?}V1*KSzSwP#Z7Zz)z^F{L?6ntK$mq?`F*K6upRMhY^sz&<+a(6Q1& zb-p%r$)wjUdcBJmPqiF}R=J-P+q?9{7DJm#RDU zDU;4xboLUH@IwP=@d%XVVCr8080dcioskR6PXjm1K-3CEO*v}Pm_=houuI6Ba&ydO z9lN$aSKi9i)cUPQAZ)@Si3Ul$CM=v!XMI_*htR?F$38yfZ1K>N+Bpbn?1yfVl(w$- zd*U(+vhsdI_d15%yv8)v7~fOJdg-{ixvdD_rqzV@evyjm=OT7@(GbEe<__Vq1It}B TgrF1qx@ZVN%Cc`muPt8zYy?O- diff --git a/src/var/lib/tyto/program/__pycache__/new.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/new.cpython-311.pyc index 6edf5f4c156cbc8119bb18a557befebf6ea7b005..b01872fc988f73481086d4e4603eb4945507781d 100644 GIT binary patch delta 161 zcmcb~dXtrRIWI340}xCVQcQikk(Y~6fm3j*?+0ckPOb){4;&0Ed<{koX)RWbHZ3*{ zU^v;F@s2r{z!fg3i(E2SxMV&sFtPA1Wm&=nX53}txxyxPkxk+Xo5Te+i5qM@4QU@( ffhxeVlf9VIGzC5|urfjk8D>VH3?@;;4RjL#{#GeO delta 161 zcmcb~dXtrRIWI340}xDM5JVH3?@;;4RjL##&Ia; diff --git a/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc index 8d00bd165b04c526d5af953a3016223d3f49afc7..f314b29dff96a4f0f7e36175d1b4cafb4a975892 100644 GIT binary patch delta 1875 zcmZ{kUrgIp6vpj1aS|tX?AS>N#QX~(q%ENY5>iw`J7~Lh(5V8n&C`Uk-eld@sv}|T z6jh2_A(bL3Xx*w&MKq+YTJ}&0iB02WuamaDV00y-N|BHz9`@#GtAzTpU8g`nrH+4J z?)i>=kA08rpTjF1!S89B!qBE>np4R-4Es|Lb~f|&;Gguppp?fXJHR9w!5|z67QrE$ z2p%CITnIP9gQ(g5*JCfD7Ey=rAw)zyq5+UnBQQ%%z#=sRtK zY3L4>@-fvKf!2uJRY8g1TzDp2pd^$gmI5jhhfI8DIuf&aRjL+J zwfZIVJ2hx0w2Q@yi&51cg7%OctJt|$PPb}rgZ4H#_JYJ{$LyKYb3-#jMfZaEj9ha6 z;85*xXpdL3obZUcPZeXZF08U0knLE)Asdl%r8)AbQng%F{?-fstIKPz zI@;RWLia#1ci{w9)j#4Ia)!9;dSB2ns7uF!cf?5j@(;eeQ(KBJEXMJj}2ed zFaJh2;TML{nPd8L?5Q>9an-&3D znpBG)TKuTeMyf>dva%$!Aa zGVkefPM7n#4C$iZT*jh{5y@YKE=J`lHWRG`TiX?Qu>kYrF>UY24cUS%B8-BFv$8?|DS0I+i{i0-?QRl$>!^5Y}kB)po zQ6G<<9UVF~qC9b4GlZgw$oDPR3H7-DIh&nKPG-j^Q{PNh7a;rGvByCxlT|+A-|^8` zE{{(pKg*6^NoKyxKHm-XW0fa-6FI6c%b4;zA5w6^s~mGRP&bf;BeMS~pSr#{?$EFR zzAYc(b^35u263w%?@GN1Z_%(_sa1Y;4^U+%FWYpX6sxD6E(@+zj72ItG)A$wJCfWP zTsCj`8q4|~sH(s0Ytd*k=S1%s=agy9iHU7xU$E?ZrLAbZFE3!MXMSQfSLj*nTNOhZaplOQluI-k5k8Pt&^htr%SiULqk)Jn-getHk53O`t`h(ysmc>z?z! zKF8L*@_O=@&ghREXT{KX@tbetYBPrYr3Z(@T%Y_i@KsbQnk5!c5(g}j4bTz~tdbot zk^`_(Bj6+f*d!<5fgLzNBM??d$u;5xPE@i!P~i?Q;JsxtG8BDt0O9#gKSQ|w9VM(vac){%`8xh>^!?X2wkyiF``;h z(2|lvHDtIKz4P93gGzfK?RlfzP|5u~RGF?`Up1+0H)OjH%b782lS(&3x>nS8Bvif=@}1R5$fx9X&4O7tIas4?GmmB;$-y0(n{%!`qXcp+6y6}(gU5zlAgqrC6_WsxRpAV~II~3ciDJUl7 ziIcPP#J)xl=oy=^FjgYU$_v(6)Ob|cC~wH$dZT}Jd7U$6`}_OoohheAAM@V2{)ER* zsQRkdh*{ll?9rW4sGP6#R|C}#R5k&bf`iC3iZv9+r4jfj2%&~ao-Vn-`XA*z(2l$4!n%*P^=u>JvwG)mG(i} zryrctHIjy;Yx!<@TqQdo*|9-(>{0@x{3;cMR1j@9L4F?nEc!GulblV;Nu$M77?o9K zIC1R(Z^N&AiK6@kqZ2w@Hv8h>{NU0%r9qWzgIt>&t8u)Mx>V{`xgg|%C#K|>98>L;2IJ(^WmI_TJzcKoa#a_LE+mq@2Bqq_S}ZWRKqBD}=lzL9Z`@QM zLMcQVkwJ7JvIS3WH0>WAAIj&?2dBrT$473bgT3K=E;-tr?k%+DMl;9VOx?{GX4i4E zt8R7~=Gp9VH(PhJhTDDI>^|(;Tlh(tZOke!8>dLWHJ(xWg!9Vp&I=aH#Q5!rp{Y+5 zpDSR#u7BzcWxy5Z*wJa^4Bwxa7`ZpC+;g?86$Kxz%(;BlhiH}lbIbps{OtN9XVb7S zUYC#XR(*OT{kT<+kHl}nLmGA@e&wZ@%(548nc8u;ZtJ%nsYaVv4lQFj*`nDoyL)MJ zp-}3nq*l&V9#$uRC~Vl$%58Tvv+eMfCZQuxxwgS)WETA|`Gm~uh+W%a=IGWKGjG>0 lBr>Bpl@GNuEdtlv(`tbQ4X??0eH2#){& diff --git a/src/var/lib/tyto/program/__pycache__/show.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/show.cpython-311.pyc index 8530f00de6bdd6591effc6fb3c36c55e000bc34b..bb27122823d677a2c967c1fd56a1236f95894635 100644 GIT binary patch delta 283 zcmbQrIhB)lIWI340}$j1E2ai)>{(o6=sPG%n~1%I9Qw*Z*XxpB;J*fo5OcqLg$i%&Wgy366RMV z%s((Nv1@>dPOT2*j?x=E{2g)=1Scd;6q_J;my@qUbcQnsE?`~2dVycxHMK;GPY>pR@ e(Bv1)^?Cvy7+4vhgcuj26XOR4>|_x)Ff;(B)>U2r delta 283 zcmbQrIhB)lIWI340}y-xyelR%CGWbJ)+I5m6_yvpOs|NU zeqdl?RRt5BTpi3Ep*J{r8uB_4Cm437btK+p<8DZuAq}d9*Q%=ocAB^c1Bv{6l> zMJamd?3<5o-n{uZ^WNLpXVH&izK>;D1g!nym!p}vzQ?`+`0nHA_pSnsTfx_{#;=3x zq9!nuG#5j!h8W74o1sthF!XDfVUH#tyr2YbxPU?xBW3A2OtaHa&XDtLq#_IWc-gwb|8i_{249+xz{g#XO z$`)Xt&sieyN6(=pg3Bfj! z)|acWdcOX$k#58qX@cSu#Z44%%7M}kc0^xkeDj8<3X4LlE&DfqRJl>UQNKduQ7Vrz z2KV_kmNp{Q?;BT4tP-qJtTLsIeH)?bY#p&9W*V=2>LNHvanjru%f(hY%Xclr39&D` z+qhzkH((<{&II|A?-S+#Z4F|TPTG5`~-Q7KE@0cxt z6OspKxoQ;H*#&~;D4H|(g{}S<0zH9^H@5x5TmE4K6aN(TPwC%kA`jygo`;W4Z>ZJF z^^kG3are{I7bl3gK*a@<$!X`OE&9L7!I|GY=leHT6uleK%GvVSdWeW)R2;LplLrYu zx;wThIYhmui8o5UQ9aq@@x%EC^QAWlAEJE7Pz)Sf=4MHH5Rw< zq=_flL`kuDAga5T0EJV;NJlhz~D5xLCSX&DSpzeuVNP zCO^V5Tl#UGC!Rs-8MJq-7?2S?TzRlkjlHwFzN)XXv&sZfcrp$cbwNO_mak~ardE7`z!3Lo#lIlHNL>t ze#iIq-RGY&=TBJgv^C+rP37<)&9LL~RVTMRVbc@tkli_s?0@63`~XK7 zk#p-t(%nR}T??!`_3}AWp44`@FoqiUl$FdUTy2{h_h>?QFos4F{PL}AF`vsahd;2MUu3`%;0;u+m9N!j z4b;6DjxotW=fiN>7$EW#m8bOc2MayKt5UD3CwIgi{gM+fwXfyAoyy-{SzgN7p~~4M zk&A=c2Z5mQ6Q6vBnwuRdPA_vZO| zzMg$j{wu3JQB}my>+@pb?k`i1vHj_l)kD+sa7RQttwMa zRT1TMm3@oJE02EsDa!k7HrU!~Z9QfAX0EmTu+%Ko$M@kE;8$ImCeoE7DKU@|SV|Eo zRZlyzuN!a2?NA=e1tJ%0w%Grc{TbAd)-AS+#wJElf}&=bphP`$d|}kNC^~mxH0=sZ zV#ZuGSFOw5-Ge=7PtQBkL6_$ga4So-5YS8lAY8tC) zqNeM)V_tF@z~x)HZmC`RCS!hVt>b8cL<>jJ(jZ#G(K3maF}g<3HG3=v1-w!-^SJm` z@yq$I=P}9=l(SLp7zK_{e1PH@B?(H}Y;xE0Ws~*Hd4Ba{VhFq}s|W9Qw!8P*_ssXO zrV~xaa+b(hmti^o5X#M)tqmh==B(A8zqg9vB7uuGTy&J_*7C8ewu1d#$pAI3G*r~i zOWl?BikZPmiYO`CfnOR5Qu9M2V+CzN$AV4-ojwc&rMY8p#yjS^wcLB5_cj(PM5x#& za(TLPynN&eELVCu86#ssYoiy$aDl)D`&3||-$0MqS`si!of(SC!7H8DySLl7&Fk1V zM|^Ww)QPCqXI;p1OG7&Mj(G{o2_h%xp7RmQ?+D`lc4NEs0T#kU2-`x~OTc$%HP>O(vkx$X?}{e zJkj#?yu*vMFL&eMa_5RsF=gv|@9uYR{=j2-g~%(mr;PV8l(qjX@bdjvwZGY#taQTN zWIJifSe_;Ftk-(!)bI1d(V2V^qEKsfqUd$qVWs_IquAQPY=p28n~k^vj;{s{~x?-v?{ z*1N_gZN;Vto3hyyHMVurxR1pc5o6xOLGvTpX#ZB@mf?T6)?BNvQP;TOI5h@!jSEuO z&c?jNi)U(1tDjkSzV=M%;e$Y$&HE2Wq5Pp9E+1}$!?io~Jkh@$bKj+)Uk`x$8el-& zW@2aMFjwvWD~Ac%7s>T;pcbGn8Soqd7F?wV=L7*Ch`Y=LIRVg9IYE>Mn#)WO5<$sj XCWxxwhRaN#UjlR={*7Jey;%MMJ(AY; diff --git a/src/var/lib/tyto/program/__pycache__/tyto.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/tyto.cpython-311.pyc index ab05e43c3dee73a489b730d668eacb90f80ea830..e930bb74518f093040085057fe0b7e0796bf1685 100644 GIT binary patch delta 221 zcmbQoF^`jPIWI340}%LCE2f%qPvnzeoG?+nhm$W#B!w}UL6d*ujylHrstlWgqEv9_^7lgQ delta 74 zcmbQoIgf*HIWI340}y<5kxmWgn#d=?*fUYRhm|pyL6dLeo;pS*O_9yZn1mQ7A7(b> Z(g7-D1mfa}lm9VK;B4S%;3(1p@&TPk5s&}? diff --git a/src/var/lib/tyto/program/__pycache__/userset.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/userset.cpython-311.pyc index beda49e2b97bb7e9a767b201c8a594e5d0195df0..058e4c4ff2aa946fe72d5d68f2bd1adbf96ad3ed 100644 GIT binary patch delta 212 zcmeyt{)3%&IWI340}#9xQcRt^k@qlDJu_#E-9={ME6l0^72VQm_-VY2wq9N&n5CgklLsExWOV$LDi)><7*u*Zt&;t&>3qr~l zI6!Cx+XjtG8deuHtnRY$Tw#-*A?J3HP5BC&@&y?Bz|6p@0#XcCH942LP)g+kgCHY1 JQ6vNO1^{YUL8AZw delta 212 zcmeyt{)3%&IWI340}w2`DVAEbk@qlDJrhTZ-bE&%D@;Ncn1mj%a(9$A#W%!16_vUo zs(lwkYJo{)Hbg|{11~!l_Xh?b(ctt!h=G;A!KtCF#jB&_B8$is7Lf}u^njiBf}qj` zb`V-nwn5^Oy5$9R%eyRGS6C!x$f;dqQM|&Ucmak!Ff(u{gA{{RP0nR5lv4V@AjpVL J6v+U+0RYc>LM;FQ diff --git a/src/var/lib/tyto/program/args.py b/src/var/lib/tyto/program/args.py index d699101..e5e1884 100644 --- a/src/var/lib/tyto/program/args.py +++ b/src/var/lib/tyto/program/args.py @@ -40,59 +40,59 @@ import langs, tyto, debug, help, new, check, userset, show # Action Arguments # #------------------# def get_action(): - global action - try: action = sys.argv[1] - except: action = "" + global action + try: action = sys.argv[1] + except: action = "" #==================# # Target arguments # #------------------# def get_target(): - global target, targets - try: target = sys.argv[2] - except: target = "" - - targets = False - if target == "all": targets = True + global target, targets + try: target = sys.argv[2] + except: target = "" + + targets = False + if target == "all": targets = True #================================# # Searching options in arguments # #--------------------------------# def get_options(): - global dlogs, force, erron - - dlogs = force = erron = False - for arg in range(1, len(sys.argv)): - dlogs = sys.argv[arg] in tyto.debug_options - force = sys.argv[arg] in tyto.force_options - erron = sys.argv[arg] in tyto.debug_errors + global dlogs, force, erron + + dlogs = force = erron = False + for arg in range(1, len(sys.argv)): + dlogs = sys.argv[arg] in tyto.debug_options + force = sys.argv[arg] in tyto.force_options + erron = sys.argv[arg] in tyto.debug_errors #===========# # Show logs # #-----------# def valid_action(): - global action - if not action in tyto.actions: - debug.out(1, "[action]", action, False, 2, False) - action = "help" + global action + if not action in tyto.actions: + debug.out(1, "[action]", action, False, 2, False) + action = "help" #==============# # Start action # #--------------# def start_process(): - # Set Lang logs - langs.load_logs_lang() - - get_options() - get_action() - get_target() - valid_action() - - do = { + # Set Lang logs + langs.load_logs_lang() + + get_options() + get_action() + get_target() + valid_action() + + do = { "help" : help.show, "check" : check.manage, "new" : new.manage, @@ -101,6 +101,6 @@ def start_process(): "stop" : userset.manage, "show" : show.manage, } - - do[action](action, target) + + do[action](action, target) diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py index db256b4..5c83af6 100644 --- a/src/var/lib/tyto/program/check.py +++ b/src/var/lib/tyto/program/check.py @@ -35,7 +35,7 @@ import sys, os from dateutil.parser import parse -import args, domain, langs, debug, post, tools +import args, domain, langs, debug, post, tools, tyto #=====================================# @@ -56,14 +56,14 @@ def ready(): # Create user work domain directories # #-------------------------------------------# def manage(action, target): - # target is "all" - if args.targets: - multiple_targets - return + # target is "all" + if args.targets: + multiple_targets + return - # target is not "all" - ready() - target.endswith(".tyto") and is_article(target) + # target is not "all" + ready() + target.endswith(".tyto") and is_article(target) #================================# @@ -71,19 +71,19 @@ def manage(action, target): # Also used with multiple (loop) # #--------------------------------# def is_article(target): - valid(target) - - # When all is OK - # Will create post database, but now, show some values - print("chk_date", chk_date) - print() - print("Final text_contents string") - for ln, line in enumerate(post.text_contents.rsplit("\n"), post.head_lines): - print(">", ln, line) - - print() - # Write to post database - cf_update_values() + valid(target) + + # When all is OK + # Will create post database, but now, show some values + print("chk_date", chk_date) + print() + print("Final text_contents string") + for ln, line in enumerate(post.text_contents.rsplit("\n"), post.head_lines): + print(">", ln, line) + + print() + # Write to post database + cf_update_values() #===========================================# @@ -91,45 +91,45 @@ def is_article(target): # In error case, exit or return if targetS # #-------------------------------------------# def valid(target): - targets = args.targets - - # Target is a tyto article format - post.is_article(target) or tools.exit(targets, post.error) - - global css - css = domain.cf.get("WEBSITE", "css") - - global headers, texts - headers = post.head_contents.rsplit("\n") - texts = post.text_contents.rsplit("\n") - - # ============= - # Head contents - # ============= - - # One Line targs in head_contents - post.error == 0 and ol_tags() or tools.exit(targets, post.error) - #Multiple and optional Tags on 3 linges - post.error == 0 and ml_tags() or tools.exit(targets, post.error) - - # ============ - # Text article - # ============ - # Start Lines - # ----------- - # Paired tags. - post.error == 0 and sl_paired("bcodes") or tools.exit(targets, post.error) - post.error == 0 and sl_paired("quotes") or tools.exit(targets, post.error) - post.error == 0 and sl_paired("parags") or tools.exit(targets, post.error) - # Single tags - post.error == 0 and titles() or tools.exit(targets, post.error) + targets = args.targets + + # Target is a tyto article format + post.is_article(target) or tools.exit(targets, post.error) + + global css + css = domain.cf.get("WEBSITE", "css") + + global headers, texts + headers = post.head_contents.rsplit("\n") + texts = post.text_contents.rsplit("\n") + + # ============= + # Head contents + # ============= + + # One Line targs in head_contents + post.error == 0 and ol_tags() or tools.exit(targets, post.error) + #Multiple and optional Tags on 3 linges + post.error == 0 and ml_tags() or tools.exit(targets, post.error) + + # ============ + # Text article + # ============ + # Start Lines + # ----------- + # Paired tags. + post.error == 0 and sl_paired("bcodes") or tools.exit(targets, post.error) + post.error == 0 and sl_paired("quotes") or tools.exit(targets, post.error) + post.error == 0 and sl_paired("parags") or tools.exit(targets, post.error) + # Single tags + post.error == 0 and titles() or tools.exit(targets, post.error) #===========================================# # Create a loop to get all .tyto articles # #-------------------------------------------# def multiple_targets(): - ready() + ready() #=====================# @@ -139,65 +139,65 @@ def multiple_targets(): # One Line needed tags # #----------------------# def ol_tags(): - global sitemap, src_uri - - sitemap = "True" - for ln, line in enumerate(headers, 1): + global sitemap, src_uri + + sitemap = "True" + for ln, line in enumerate(headers, 1): - if not line or line.isspace(): continue - if line.startswith("#"): - post.stats_tyto_head_coms += 1 - continue + if not line or line.isspace(): continue + if line.startswith("#"): + post.stats_tyto_head_coms += 1 + continue - # One Line tags (Must be set) - # =========================== - if not post.title[1] and line.startswith(post.title[0]): - post.title = (post.title[0], ol_tag_value(line, False)) + # One Line tags (Must be set) + # =========================== + if not post.title[1] and line.startswith(post.title[0]): + post.title = (post.title[0], ol_tag_value(line, False)) - elif not post.about[1] and line.startswith(post.about[0]): - post.about = (post.about[0], ol_tag_value(line, False)) - - elif not post.date[1] and line.startswith(post.date[0]): - post.date = (post.date[0], ol_tag_value(line, False)) - - elif not post.author[1] and line.startswith(post.author[0]): - post.author = (post.author[0], ol_tag_value(line, True)) + elif not post.about[1] and line.startswith(post.about[0]): + post.about = (post.about[0], ol_tag_value(line, False)) - elif not post.tags[1] and line.startswith(post.tags[0]): - post.tags = (post.tags[0], ol_tag_value(line, True)) - - - # Optional tags - # ------------- - elif not post.logo[1] and line.startswith(post.logo[0]): - post.logo = (post.logo[0], ol_tag_value(line, False)) - logo_ln = ln - - elif line.startswith(post.nositemap): - sitemap = "False" - - - # Sets are done from loop - # Check if tag value exists - # ========================= - if not is_ol_tag(post.date[0], post.date[1]): return False - if not is_valid_date(post.date[1]): return False - if not is_ol_tag(post.title[0], post.title[1]): return False - if not is_ol_tag(post.about[0], post.about[1]): return False - if not is_ol_tag(post.author[0], post.author[1]): return False - if not is_ol_tag(post.tags[0], post.tags[1]): return False - - # Default domain logo for this post - src_uri = "%stemplate/%s"%(domain.www_url, domain.logo) - # logo is set with specific uri - if is_value2_file_exists(logo_ln, "logo:", post.logo[1]): - src_uri = "%s%s"%(domain.www_url, src_uri) - else: - return False - post.logo = (post.logo[0], src_uri) - post.cf.set("HEADERS", "logo", src_uri) - - return True + elif not post.date[1] and line.startswith(post.date[0]): + post.date = (post.date[0], ol_tag_value(line, False)) + + elif not post.author[1] and line.startswith(post.author[0]): + post.author = (post.author[0], ol_tag_value(line, True)) + + elif not post.tags[1] and line.startswith(post.tags[0]): + post.tags = (post.tags[0], ol_tag_value(line, True)) + + + # Optional tags + # ------------- + elif not post.logo[1] and line.startswith(post.logo[0]): + post.logo = (post.logo[0], ol_tag_value(line, False)) + logo_ln = ln + + elif line.startswith(post.nositemap): + sitemap = "False" + + + # Sets are done from loop + # Check if tag value exists + # ========================= + if not is_ol_tag(post.date[0], post.date[1]): return False + if not is_valid_date(post.date[1]): return False + if not is_ol_tag(post.title[0], post.title[1]): return False + if not is_ol_tag(post.about[0], post.about[1]): return False + if not is_ol_tag(post.author[0], post.author[1]): return False + if not is_ol_tag(post.tags[0], post.tags[1]): return False + + # Default domain logo for this post + src_uri = "%stemplate/%s"%(domain.www_url, domain.logo) + # logo is set with specific uri + if is_value2_file_exists(logo_ln, "logo:", post.logo[1]): + src_uri = "%s%s"%(domain.www_url, src_uri) + else: + return False + post.logo = (post.logo[0], src_uri) + post.cf.set("HEADERS", "logo", src_uri) + + return True #===========================================# @@ -206,18 +206,18 @@ def ol_tags(): # set new value, removing spaces (strip) # #-------------------------------------------# def ol_tag_value(line, commas): - value = line.rsplit(":")[1].lstrip() - - # reformat comma separated items, removing first spaces - if commas: - tuple_values = value.rsplit(",") - value = "" - for i, item in enumerate(tuple_values): + value = line.rsplit(":")[1].lstrip() + + # reformat comma separated items, removing first spaces + if commas: + tuple_values = value.rsplit(",") + value = "" + for i, item in enumerate(tuple_values): value = value + item.strip() if i != len(tuple_values) - 1: value = value + "," - - return value + + return value #===========================# @@ -225,11 +225,11 @@ def ol_tag_value(line, commas): # Return True/False # #---------------------------# def is_ol_tag(tag, value): - if not value: - post.error = debug.out(51, "%s ?"%tag, post.uri, True, 2, False) - return False - - return True + if not value: + post.error = debug.out(51, "%s ?"%tag, post.uri, True, 2, False) + return False + + return True #======================================# @@ -238,162 +238,180 @@ def is_ol_tag(tag, value): # Return True/False # #--------------------------------------# def is_valid_date(date): - global chk_date - - try: - parse(date) - chk_date = tools.nowdate() - return True - except: - post.error = debug.out(50, "%s"%date, post.uri, True, 2, False) - return False + global chk_date + + try: + parse(date) + chk_date = tools.nowdate() + return True + except: + post.error = debug.out(50, "%s"%date, post.uri, True, 2, False) + return False #============================# # multiple and optional Tags # # Written using 3 lines # +# Tags are stric start line # #----------------------------# def ml_tags(): - global value1 - - value1 = "" - R_tag = post.ml_tags[3] # raw: - C_tag = post.ml_tags[4] # code: - - c = 0 # Continue for next x lines, as tags are 3 lines values - for ln, line in enumerate(headers): + #global value1 + + c = 0 # Continue for next x lines, as tags are 3 lines values + + for ln, line in enumerate(headers): if c != 0: c -= 1 continue - - if not line or line.isspace() or line.startswith("#"): continue - # link: - if line.startswith(post.ml_tags[0]): - post.stats_links += 1 - if not ml_tag_values(ln, post.ml_tags[0], post.stats_links): - return False # value errors + if line.startswith(post.ml_tags): + tag = line.rsplit(":")[0] + ":" + post.ml_tags_stats[tag] = post.ml_tags_stats[tag] + 1 - c = 2 ; continue - - # file: - elif line.startswith(post.ml_tags[2]): - post.stats_files += 1 - if not ml_tag_values(ln, post.ml_tags[2], post.stats_files): - return False # value errors - - c = 2 ; continue - - # image: - elif line.startswith(post.ml_tags[1]): - post.stats_images += 1 - if not ml_tag_values(ln, post.ml_tags[1], post.stats_images): - return False # value errors - # image: logo is reserved for post logo - if value1 == "logo": - debug.out(56, "%s) 'logo'"%(ln+1), post.uri, True, 2, False) - return False + if not ml_tag_values(ln, tag, post.ml_tags_stats[tag]): + return False - c = 2 ; continue - - # ABBRS: - elif line.startswith(post.ml_tags[5]): - post.stats_abbrs += 1 - if not ml_tag_values(ln, post.ml_tags[5], post.stats_abbrs): - return False # value errors - - c = 2 ; continue + c = 2 + continue - - # value1 must not starts with "_", as used by Tyto - if value1.startswith("_"): - debug.out(56, "%s) '_...'"%(ln+1), post.uri, True, 2, False) - return False - - return True + return True #========================================# # Get tag 3 lines values # -# Check if 2nd, 3rd lines starts with a: # +# Check if 2nd, 3rd lines starts with: # # - tag, comment or are empty # -# Set globals value # +# Create var and val for post database # # Return True/False (if no value) # #----------------------------------------# def ml_tag_values(ln, tag, stats): - global value1, value2 - - # Get 3 lines values - value1 = headers[ln].rsplit(":")[1].lstrip() - value2 = headers[ln+1].lstrip() - value3 = headers[ln+2].lstrip() - - # Check values (not empty or begins with a tag) - if not value1: - post.error = \ - debug.out(51, "%s) %s 1/3"%(ln+1, tag), post.uri, True, 2, False) - return False - - if not value2 or value2.startswith(post.ml_tags): - post.error = \ - debug.out(51, "%s) %s 2/3"%(ln+2, tag), post.uri, True, 2, False) - return False - - if not value3 or value3.startswith(post.ml_tags): - post.error = \ - debug.out(51, "%s) %s 3/3"%(ln+3, tag), post.uri, True, 2, False) - return False - - # Convert value1 in header with tyto_value1 in text - tyto_value = post.ml_marks[tag] + value1 - - # CHeck if value is in text and to stats or return error - if post.text_contents.find(tyto_value) == -1: - post_error = debug.out(51, tyto_value, post.uri, True, 2, False) - return False - - # Check value2 link for some tags (file, image...) - if tag in post.value2s_uri \ - and not value2.startswith(post.value2s_ext_uris): - if not is_value2_file_exists(ln+2, tag, value2): - return False - - # Convert values to HTML (put in post database) - link_var = "%s_%s"%(tag.replace(":", ""), stats) - html_var = "html_%s"%stats + global value1, value2 + + # Get 3 lines values + value1 = headers[ln].rsplit(":")[1].lstrip() + value2 = headers[ln+1].lstrip() + value3 = headers[ln+2].lstrip() + + # Check values (not empty or begins with a tag) + # value1 + # ------ + if not value1: + post.error = \ + debug.out(51, "%s) %s 1/3"%(ln+1, tag), post.uri, True, 2, False) + return False + + # value1 must not starts or contains:o + elif value1.startswith("_"): + debug.out(56, "%s) '_...'"%(ln+1), post.uri, True, 2, False) + return False + + # Specific for image: logo name is reserved + elif tag == post.ml_tags[1] and value1 == "logo": + debug.out(56, "%s) 'logo'"%(ln+1), post.uri, True, 2, False) + return False + + # value2 + # ------ + if not value2 or value2.startswith(post.ml_tags): + post.error = \ + debug.out(51, "%s) %s 2/3"%(ln+2, tag), post.uri, True, 2, False) + return False + + # value3 + # ------ + if not value3 or value3.startswith(post.ml_tags): + post.error = \ + debug.out(51, "%s) %s 3/3"%(ln+3, tag), post.uri, True, 2, False) + return False + + # No error with values + # Convert value1 in header with tyto_value1 in text + tyto_value = post.ml_tags_marks[tag] + value1 + + # CHeck if value is in text and to stats or return error + if post.text_contents.find(tyto_value) == -1: + post_error = debug.out(51, tyto_value, post.uri, True, 2, False) + return False + + # Check value2 link for some tags (file, image...) + if tag in post.value2s_uri \ + and not value2.startswith(post.value2s_ext_uris) \ + and not is_value2_file_exists(ln+2, tag, value2): + return False - if tag == post.ml_tags[0]: - section = "LINKS" - post.stats_text_links += post.text_contents.count(tyto_value) - html_value = '%s'%( - value2, css, "%%s", value3, value1 - ) - - elif tag == post.ml_tags[2]: - section = "FILES" - post.stats_text_files += post.text_contents.count(tyto_value) - html_value = '%s'%( - value2, css, "%%s", value3, value1 - ) - - elif tag == post.ml_tags[1]: - section = "IMAGES" - post.stats_text_images += post.text_contents.count(tyto_value) - html_value = '%s'%( - value2, "%%s", "%%s", value3, "%%s" - ) - - elif tag == post.ml_tags[5]: - section = "ABBRS" - post.stats_text_abbrs += post.text_contents.count(tyto_value) - html_value = '%s'%( - domain.css, value2, value3 - ) + + #-----------------------------------------------# + # Convert values to HTML (put in post database) # + #-----------------------------------------------# + link_var = "%s_%s"%(tag.replace(":", ""), stats) + html_var = "html_%s"%stats + + # link: + if tag == post.ml_tags[0]: + section = "LINKS" + post.stats_text_links += post.text_contents.count(tyto_value) + html_value = '%s'%( + value2, css, "%%s", value3, value1 + ) + + # file: + elif tag == post.ml_tags[2]: + section = "FILES" + post.stats_text_files += post.text_contents.count(tyto_value) + html_value = '%s'%( + value2, css, "%%s", value3, value1 + ) + + # image: + elif tag == post.ml_tags[1]: + section = "IMAGES" + post.stats_text_images += post.text_contents.count(tyto_value) + html_value = '%s'%( + value2, "%%s", "%%s", value3, "%%s" + ) + + # raw: (content file converted to base64) + elif tag == post.ml_tags[3]: + section = "RAWS" + post.stats_text_raws += post.text_contents.count(tyto_value) + html_value = ""%value3 + with open(value2_uri, "r") as f: + html_value = "%s\n%s"%(html_value, f.read()) + + html_value = tools.b64_convert("encode", html_value) + + # code: (content file converted to HTML + base64) + elif tag == post.ml_tags[4]: + section = "CODES" + post.stats_text_codes += post.text_contents.count(tyto_value) + htmlbcode = ""%value3 + with open(value2_uri, "r") as f: + for line in f.read().rsplit("\n"): + line = tools.convert_html_signs(line) + line = '
  • %s
  • '%(domain.css, line) + htmlbcode = "%s\n%s"%(htmlbcode, line) + + html_value = tyto.pre_bcode%( + domain.css, domain.css, domain.css, + htmlbcode + ) + print() + print(html_value) + print() + html_value = tools.b64_convert("encode", html_value) + + # abbr: + elif tag == post.ml_tags[5]: + section = "ABBRS" + post.stats_text_abbrs += post.text_contents.count(tyto_value) + html_value = '%s'%( + domain.css, value2, value3 + ) - post.cf.set(section, link_var, tyto_value) - post.cf.set(section, html_var, html_value) - - return True + post.cf.set(section, link_var, tyto_value) + post.cf.set(section, html_var, html_value) + + return True #================================# @@ -404,45 +422,45 @@ def ml_tag_values(ln, tag, stats): # - ... for post directory # #--------------------------------# def is_value2_file_exists(ln, tag, val2): - global value2, src_uri - - # uri "@..." means generic folders - if val2[0].startswith("@"): - if val2[1] == "/": val2 = val2[2:] - else: val2 = val2[1:] + global value2, src_uri, value2_uri + + # uri "@..." means generic folders + if val2[0].startswith("@"): + if val2[1] == "/": val2 = val2[2:] + else: val2 = val2[1:] - #Set directory for files - test_uri = os.path.join(domain.wrk_files + val2) - value2 = src_uri = os.path.join("/files", val2) + #Set directory for files + value2_uri = os.path.join(domain.wrk_files + val2) + value2 = src_uri = os.path.join("/files", val2) - # Set directory for images in /images - if tag == post.ml_tags[1] or tag == post.logo[0]: # image: - test_uri = os.path.join(domain.wrk_images, val2) - value2 = src_uri = os.path.join("/images", val2) - - # uri "/..." means from wrk root folder - elif val2[0].startswith("/"): - val2 = val2[1:] - test_uri = os.path.join(domain.wrk_articles, val2) - src_uri = val2 - - # uri "..." means from legacy post folder - else: - test_uri = os.path.dirname(post.uri) + "/" + val2 - value2 = "./" + val2 - src_uri = test_uri.rsplit("articles/")[1] + # Set directory for images in /images + if tag == post.ml_tags[1] or tag == post.logo[0]: # image: + value2_uri = os.path.join(domain.wrk_images, val2) + value2 = src_uri = os.path.join("/images", val2) + + # uri "/..." means from wrk root folder + elif val2[0].startswith("/"): + val2 = val2[1:] + value2_uri = os.path.join(domain.wrk_articles, val2) + src_uri = val2 + + # uri "..." means from legacy post folder + else: + value2_uri = os.path.dirname(post.uri) + "/" + val2 + value2 = "./" + val2 + src_uri = value2_uri.rsplit("articles/")[1] - # Check if file exists - if not os.path.exists(test_uri): - post.error = \ - debug.out(5, "%s) %s"%(ln, tag), test_uri, True, 2, False) - return False - - # Add file to [SOURCE_FILES] post database - post.stats_total_files += 1 - post.cf.set("SOURCE_FILES", "file_%s"%post.stats_total_files, src_uri) - - return True + # Check if file exists + if not os.path.exists(value2_uri): + post.error = \ + debug.out(5, "%s) %s"%(ln, tag), value2_uri, True, 2, False) + return False + + # Add file to [SOURCE_FILES] post database + post.stats_total_files += 1 + post.cf.set("SOURCE_FILES", "file_%s"%post.stats_total_files, src_uri) + + return True #=====================# @@ -459,101 +477,99 @@ def is_value2_file_exists(ln, tag, val2): # Return True/False # #----------------------------------------# def sl_paired(markers): - global texts - - new_text_contents = "" - opened = closed = in_tag = False - stats_opened = stats_closed = 0 - tags = () - - if markers == "bcodes" : tags = post.bcodes - elif markers == "quotes" : tags = post.quotes - elif markers == "parags" : tags = post.parags - - # loop lines in text_contents - for ln, line in enumerate(texts, post.head_lines + 1): + global texts + + new_text_contents = "" + opened = closed = in_tag = False + stats_opened = stats_closed = 0 + tags = () + + if markers == "bcodes" : tags = post.bcodes + elif markers == "quotes" : tags = post.quotes + elif markers == "parags" : tags = post.parags + + # loop lines in text_contents + for ln, line in enumerate(texts, post.head_lines + 1): - # Tag was closed, but not in_tag content line - if closed and in_tag: - in_tag = False - - # Tag is opened - if line.startswith(tags[0]): - # Tag was already opened - if opened: - post.error = \ - debug.out(53, "%s) %s ... %s"%( - ln+1, - tags[0], tags[1] - ), post.uri, True, 2, False) - return False + # Tag was closed, but not in_tag content line + if closed and in_tag: + in_tag = False - # check next line if exists or is a closed tag - try: - next_line = post.contents.rsplit("\n")[ln] - if next_line.startswith(tags[1]): + # Tag is opened + if line.startswith(tags[0]): + # Tag was already opened + if opened: + post.error = \ + debug.out(53, "%s) %s ... %s"%( + ln+1, + tags[0], tags[1] + ), post.uri, True, 2, False) + return False + + # check next line if exists or is a closed tag + try: + next_line = post.contents.rsplit("\n")[ln] + if next_line.startswith(tags[1]): + post.error = \ + debug.out(55, "%s) '%s'"%(ln, tags[0]), post.uri, True, 2, False) + return False + except: post.error = \ debug.out(55, "%s) '%s'"%(ln, tags[0]), post.uri, True, 2, False) return False - except: - post.error = \ - debug.out(55, "%s) '%s'"%(ln, tags[0]), post.uri, True, 2, False) - return False - opened = in_tag = True - closed = False - stats_opened += 1 - - # Tag is closed - if line.startswith(tags[1]): - # Tag was already closed - if closed: - post.error = \ - debug.out(53, "%s) %s ... %s"%( - ln+1, - tags[0], tags[1] - ), post.uri, True, 2, False) - return False + opened = in_tag = True + closed = False + stats_opened += 1 - closed = True - opened = False - stats_closed += 1 - - - if in_tag: - # Contents must be indented - if not line.startswith(tags): - if len(line) - len(line.lstrip()) < 3: - post.error = \ - debug.out(54, "%s) '\t'%s..."%( - ln+1, line[0:10] + # Tag is closed + if line.startswith(tags[1]): + # Tag was already closed + if closed: + post.error = \ + debug.out(53, "%s) %s ... %s"%( + ln+1, + tags[0], tags[1] ), post.uri, True, 2, False) - return False - line = "" - - # Create new string, removing in_tag line if in bcodes or quotes - if markers in post.raw_contents: - if not new_text_contents: new_text_contents = line - else: new_text_contents = "%s\n%s"%(new_text_contents, line) - - texts = new_text_contents.rsplit("\n") - - # Create post.stats - post.cf.set("STATS_TEXTS", markers, str(stats_opened)) - - return True + return False + + closed = True + opened = False + stats_closed += 1 + + + if in_tag: + # Contents must be indented + if not line.startswith(tags): + if len(line) - len(line.lstrip()) < 3: + post.error = \ + debug.out(54, "%s) '\t'%s..."%( + ln+1, line[0:10] + ), post.uri, True, 2, False) + return False + line = "" + + # Create new string, removing in_tag line if in bcodes or quotes + if markers in post.raw_contents: + if not new_text_contents: new_text_contents = line + else: new_text_contents = "%s\n%s"%(new_text_contents, line) + + texts = new_text_contents.rsplit("\n") + + # Create post.stats + post.cf.set("STATS_TEXTS", markers, str(stats_opened)) + + return True #============================# # Check optional title tags # # Count tyto + html comments # -# Add stat for logo # +# Add stat for _image:logo # # Return True/False # #----------------------------# def titles(): for ln, line in enumerate(texts, post.head_lines + 1): - if not line or line.isspace(): continue - # legacy Tyto Titles if line.startswith(post.tyto_titles): if not line[3:]: @@ -563,31 +579,49 @@ def titles(): # Avoic wanting #6 - #9 (but accept #1x.. #5x.. as comments...) elif line[1].isdigit() and int(line[1]) >= 6: - post.error = \ - debug.out(52, "%s) %s..."%(ln, line[0:10]), post.uri, True, 1, False) - return False + post.error = \ + debug.out(52, "%s) %s..."%(ln, line[0:10]), post.uri, True, 1, False) + return False post.stats_titles += 1 + + # Create html value for this title in database + link_var = "title_%s"%post.stats_titles + post.cf.set("TITLES", link_var, line) + + html_var = "html_%s"%post.stats_titles + mark = line[0:2] + title = line[3:] + html_val = post.html_titles[mark]%(domain.css, title) + post.cf.set("TITLES", html_var, html_val) # Count Tyto Comments elif line.lstrip().startswith("#"): - post.stats_tyto_text_coms += 1 + post.stats_tyto_text_coms += 1 # Count HTML comments elif line.lstrip().startswith(post.text_comments): - post.stats_html_coms += 1 - + post.stats_html_coms += 1 + # Convert tyto commented marker to HTML + if line.lstrip().startswith(post.text_comments[0]): + real_com = line.lstrip()[3:] + link_var = "comm_%s"%post.stats_html_coms + post.cf.set("COMMENTS", link_var, line.lstrip()) + html_var = "html_%s"%post.stats_html_coms + post.cf.set("COMMENTS", html_var, ''%real_com) + + # Add stat + html for [IMAGES] when user wants to show logo in post elif line.lstrip().startswith("_image:logo"): - post.stats_text_images += 1 - link_var = "image_%s"%(post.stats_images+1) - link_val = "_image:logo" - html_var = "html_%s"%(post.stats_images+1) - html_val = '%s'%( - post.logo[1], "%%s", "%%s", post.title[1], "%%s" - ) - post.cf.set("IMAGES", link_var, link_val) - post.cf.set("IMAGES", html_var, html_val) + post.stats_text_images += 1 + link_var = "image_%s"%(post.ml_tags_stats["image:"] + 1) + link_val = "_image:logo" + html_var = "html_%s"%(post.ml_tags_stats["image:"] + 1) + html_val = '%s'%( + post.logo[1], "%%s", "%%s", post.title[1], "%%s" + ) + post.cf.set("IMAGES", link_var, link_val) + post.cf.set("IMAGES", html_var, html_val) return True @@ -596,54 +630,58 @@ def titles(): # Update post configuration file # #--------------------------------# def cf_update_values(): - post.date = ("date:", tools.local_date(post.date[1])) - - post.cf.set("DOMAIN", "name", domain.name) - - post.cf.set("FILE", "id", post.uri_id) - post.cf.set("FILE", "uri", post.uri) - post.cf.set("FILE", "db", post.cf_uri) - post.cf.set("FILE", "target", post.wrk_target) - - post.cf.set("HEADERS", "title", post.title[1]) - post.cf.set("HEADERS", "about", post.about[1]) - post.cf.set("HEADERS", "date", post.date[1]) - post.cf.set("HEADERS", "tags", post.tags[1]) - post.cf.set("HEADERS", "authors", post.author[1]) - post.cf.set("HEADERS", "sitemap", str(sitemap)) - - post.cf.set("CHECK", "hash", post.wrk_id) - post.cf.set("CHECK", "date", chk_date) - post.cf.set("CHECK", "static", str(domain.static)) - - post.cf.set("WIP", "web", "%s%s"%(domain.wip_url, post.wrk_target)) - post.cf.set("WIP", "uri", "%s%s"%(domain.wip, post.wrk_target)) - - post.cf.set("WWW", "web", "%s%s"%(domain.www_url, post.wrk_target)) - post.cf.set("WWW", "uri", "%s%s"%(domain.www, post.wrk_target)) - - stats_tyto_all_coms = post.stats_tyto_text_coms + post.stats_tyto_head_coms - post.cf.set("STATS_FILE", "lines", str(post.lines)) - post.cf.set("STATS_FILE", "tyto_coms", str(stats_tyto_all_coms)) - post.cf.set("STATS_FILE", "files", str(post.stats_total_files)) - - post.cf.set("STATS_HEADERS", "lines", str(post.head_lines)) - post.cf.set("STATS_HEADERS", "tyto_coms", str(post.stats_tyto_head_coms)) - post.cf.set("STATS_HEADERS", "links", str(post.stats_links)) - post.cf.set("STATS_HEADERS", "files", str(post.stats_files)) - post.cf.set("STATS_HEADERS", "images", str(post.stats_images)) - post.cf.set("STATS_HEADERS", "abbrs", str(post.stats_abbrs)) - - post.cf.set("STATS_TEXTS", "lines", str(post.text_lines)) - post.cf.set("STATS_TEXTS", "tyto_coms", str(post.stats_tyto_text_coms)) - post.cf.set("STATS_TEXTS", "html_coms", str(post.stats_html_coms)) - post.cf.set("STATS_TEXTS", "titles", str(post.stats_titles)) - post.cf.set("STATS_TEXTS", "links", str(post.stats_text_links)) - post.cf.set("STATS_TEXTS", "files", str(post.stats_text_files)) - post.cf.set("STATS_TEXTS", "images", str(post.stats_text_images)) - post.cf.set("STATS_TEXTS", "abbrs", str(post.stats_text_abbrs)) - - with open(post.cf_uri, "w") as f: - post.cf.write(f) + post.date = ("date:", tools.local_date(post.date[1])) + + post.cf.set("DOMAIN", "name", domain.name) + + post.cf.set("FILE", "id", post.uri_id) + post.cf.set("FILE", "uri", post.uri) + post.cf.set("FILE", "db", post.cf_uri) + post.cf.set("FILE", "target", post.wrk_target) + + post.cf.set("HEADERS", "title", post.title[1]) + post.cf.set("HEADERS", "about", post.about[1]) + post.cf.set("HEADERS", "date", post.date[1]) + post.cf.set("HEADERS", "tags", post.tags[1]) + post.cf.set("HEADERS", "authors", post.author[1]) + post.cf.set("HEADERS", "sitemap", str(sitemap)) + + post.cf.set("CHECK", "hash", post.wrk_id) + post.cf.set("CHECK", "date", chk_date) + post.cf.set("CHECK", "static", str(domain.static)) + + post.cf.set("WIP", "web", "%s%s"%(domain.wip_url, post.wrk_target)) + post.cf.set("WIP", "uri", "%s%s"%(domain.wip, post.wrk_target)) + + post.cf.set("WWW", "web", "%s%s"%(domain.www_url, post.wrk_target)) + post.cf.set("WWW", "uri", "%s%s"%(domain.www, post.wrk_target)) + + stats_tyto_all_coms = post.stats_tyto_text_coms + post.stats_tyto_head_coms + post.cf.set("STATS_FILE", "lines", str(post.lines)) + post.cf.set("STATS_FILE", "tyto_coms", str(stats_tyto_all_coms)) + post.cf.set("STATS_FILE", "files", str(post.stats_total_files)) + + post.cf.set("STATS_HEADERS", "lines", str(post.head_lines)) + post.cf.set("STATS_HEADERS", "tyto_coms", str(post.stats_tyto_head_coms)) + post.cf.set("STATS_HEADERS", "links", str(post.ml_tags_stats["link:"])) + post.cf.set("STATS_HEADERS", "files", str(post.ml_tags_stats["file:"])) + post.cf.set("STATS_HEADERS", "images", str(post.ml_tags_stats["image:"])) + post.cf.set("STATS_HEADERS", "abbrs", str(post.ml_tags_stats["abbr:"])) + post.cf.set("STATS_HEADERS", "codes", str(post.ml_tags_stats["code:"])) + post.cf.set("STATS_HEADERS", "raws", str(post.ml_tags_stats["raw:"])) + + post.cf.set("STATS_TEXTS", "lines", str(post.text_lines)) + post.cf.set("STATS_TEXTS", "tyto_coms", str(post.stats_tyto_text_coms)) + post.cf.set("STATS_TEXTS", "html_coms", str(post.stats_html_coms)) + post.cf.set("STATS_TEXTS", "titles", str(post.stats_titles)) + post.cf.set("STATS_TEXTS", "links", str(post.stats_text_links)) + post.cf.set("STATS_TEXTS", "files", str(post.stats_text_files)) + post.cf.set("STATS_TEXTS", "images", str(post.stats_text_images)) + post.cf.set("STATS_TEXTS", "abbrs", str(post.stats_text_abbrs)) + post.cf.set("STATS_TEXTS", "codes", str(post.stats_text_codes)) + post.cf.set("STATS_TEXTS", "raws", str(post.stats_text_raws)) + + with open(post.cf_uri, "w") as f: + post.cf.write(f) diff --git a/src/var/lib/tyto/program/debug.py b/src/var/lib/tyto/program/debug.py index 6dedfca..4aaf6d0 100644 --- a/src/var/lib/tyto/program/debug.py +++ b/src/var/lib/tyto/program/debug.py @@ -47,32 +47,32 @@ import langs, args # stop to sys exit with nbr if True # #-----------------------------------# def out(nbr, var, val, show, color, stop): - args.get_options() - if not show: - # Show only warn and error logs - show = args.dlogs or args.erron and color > 0 - - if not show: - return nbr - - # COlors - CS = '\033[0;0m' # Unset - CL = '\033[0;2m' # Gray - CB = '\033[1;34m' # Blue - CC = '\033[1;36m' # Cyan - CR = '\033[1;31m' # Red - CG = '\033[1;32m' # Green - CY = '\033[1;33m' # Yellow - CP = '\033[1;35m' # Pink - - # Color of "*" - SC = CL # Default gray - if color == 0: SC = CG - elif color == 1: SC = CY - elif color == 2: SC = CR - - # Messages for logs - messages = \ + args.get_options() + if not show: + # Show only warn and error logs + show = args.dlogs or args.erron and color > 0 + + if not show: + return nbr + + # COlors + CS = '\033[0;0m' # Unset + CL = '\033[0;2m' # Gray + CB = '\033[1;34m' # Blue + CC = '\033[1;36m' # Cyan + CR = '\033[1;31m' # Red + CG = '\033[1;32m' # Green + CY = '\033[1;33m' # Yellow + CP = '\033[1;35m' # Pink + + # Color of "*" + SC = CL # Default gray + if color == 0: SC = CG + elif color == 1: SC = CY + elif color == 2: SC = CR + + # Messages for logs + messages = \ { # ERRORS (1-100) 1 : langs.logs.err_arg, @@ -115,23 +115,22 @@ def out(nbr, var, val, show, color, stop): 209 : langs.logs.domain_on, 255 : langs.logs.later, } - - - # Print, acoording to parameters - print("%s*%s %s%s%s > %s%s%s < %s%s%s"%( + + + # Print, acoording to parameters + print("%s*%s %s%s%s > %s%s%s < %s%s%s"%( SC, CS, CL, messages[nbr], CS, CB, var, CS, CC, val, CS ) - ) - - - # Exit if stop = True - if stop: - if nbr >= 200: - nbr = 0 - sys.exit(nbr) - - return nbr + ) + + + # Exit if stop = True + if stop: + if nbr >= 200: nbr = 0 + sys.exit(nbr) + + return nbr diff --git a/src/var/lib/tyto/program/domain.py b/src/var/lib/tyto/program/domain.py index 1a4b6b1..f7c98cb 100644 --- a/src/var/lib/tyto/program/domain.py +++ b/src/var/lib/tyto/program/domain.py @@ -40,8 +40,8 @@ import debug, tyto, tools, forms, langs # Exit if directory name is compatible with a domain name # #---------------------------------------------------------# def compatible_name(): - if len(name.rsplit(".")) <= 1: - debug.out(3, "abc.tld", name, True, 2, True) + if len(name.rsplit(".")) <= 1: + debug.out(3, "abc.tld", name, True, 2, True) #================================# @@ -49,13 +49,13 @@ def compatible_name(): # As needed, exit if not exists # #--------------------------------# def cf_load(): - global cf - - cf_exists() or sys.exit(100) - - cf = False - cf = configparser.ConfigParser() - cf.read(cf_uri) + global cf + + cf_exists() or sys.exit(100) + + cf = False + cf = configparser.ConfigParser() + cf.read(cf_uri) #=====================================# @@ -63,29 +63,29 @@ def cf_load(): # As needed, exit if not exists # #-------------------------------------# def ult_cf_load(): - global ult_cf - - ult_cf = False - if not os.path.exists(ult_cf_uri): - tools.create_file(ult_cf_uri, tyto.ini_domain_user) - - ult_cf = configparser.ConfigParser() - ult_cf.read(ult_cf_uri) + global ult_cf + + ult_cf = False + if not os.path.exists(ult_cf_uri): + tools.create_file(ult_cf_uri, tyto.ini_domain_user) + + ult_cf = configparser.ConfigParser() + ult_cf.read(ult_cf_uri) #===================================# # Load User local Domains List File # #-----------------------------------# def ult_dlf_load(): - global ult_dlf - - # User Domains list file - ult_dlf = False - if not os.path.exists(ult_dlf_uri): - tools.create_file(ult_dlf_uri, tyto.ini_domains_list) - - ult_dlf = configparser.ConfigParser() - ult_dlf.read(ult_dlf_uri) + global ult_dlf + + # User Domains list file + ult_dlf = False + if not os.path.exists(ult_dlf_uri): + tools.create_file(ult_dlf_uri, tyto.ini_domains_list) + + ult_dlf = configparser.ConfigParser() + ult_dlf.read(ult_dlf_uri) #===========================================# @@ -94,36 +94,36 @@ def ult_dlf_load(): # return True or False #-------------------------------------------# def cf_exists(): - global shown_ok, shown_no - - if os.path.exists(cf_uri): - try: shown_ok - except: debug.out(202, name, cf_uri, False, 0, False) - shown_ok = True - return True - else: - try: shown_no - except: debug.out(104, "False", cf_uri, True, 1, False) - shown_no = True - compatible_name() - return False + global shown_ok, shown_no + + if os.path.exists(cf_uri): + try: shown_ok + except: debug.out(202, name, cf_uri, False, 0, False) + shown_ok = True + return True + else: + try: shown_no + except: debug.out(104, "False", cf_uri, True, 1, False) + shown_no = True + compatible_name() + return False #=========================================# # Guess and return wip_url from name # #-----------------------------------------# def create_wip_url(): - www_url = "https://www-wip.%s/" - len_cn = name.count(".") - - # Domain name Format: a.b - if len_cn == 1: - return www_url%name - - # Domain name format: (at least) a.b.c - len_cn = len(name.rsplit(".")[0]) + 1 - tld = name[len_cn:] - return www_url%tld + www_url = "https://www-wip.%s/" + len_cn = name.count(".") + + # Domain name Format: a.b + if len_cn == 1: + return www_url%name + + # Domain name format: (at least) a.b.c + len_cn = len(name.rsplit(".")[0]) + 1 + tld = name[len_cn:] + return www_url%tld #==========================================# @@ -134,41 +134,41 @@ def create_wip_url(): # If not User domains list file, create it # #------------------------------------------# def cf_create(): - compatible_name() - - # This fonction is only called with "new domain" argument - # If a conf already exists, show important RESET log - if cf_exists(): - debug.out(102, "!?", cf_uri, True, 1, False) + compatible_name() + + # This fonction is only called with "new domain" argument + # If a conf already exists, show important RESET log + if cf_exists(): + debug.out(102, "!?", cf_uri, True, 1, False) - # Ask User to create new domain. Will exit if not ok. - forms.ask_domain_shortname(name) - - # Create default files - tools.create_file(cf_uri, ini_template%name) - tools.create_dirs(ult_dir) - tools.create_file(ult_cf_uri, tyto.ini_domain_user) - - # User Domains list file - if not os.path.exists(ult_dlf_uri): - tools.create_file(ult_dlf_uri, tyto.ini_domains_list) - - # Ask user for domain settings - cf_load() - forms.ask_domain_title(True) - forms.ask_domain_date(True) - forms.ask_domain_about(True) - forms.ask_domain_mail(True) - forms.ask_domain_tags(True) - - # Set default lang, from config file or system lang - forms.ask_domain_lang(True) - - # Set server directory - forms.ask_domain_server(True) - - # Update Domain Configuration file - cf_update_values(True) + # Ask User to create new domain. Will exit if not ok. + forms.ask_domain_shortname(name) + + # Create default files + tools.create_file(cf_uri, ini_template%name) + tools.create_dirs(ult_dir) + tools.create_file(ult_cf_uri, tyto.ini_domain_user) + + # User Domains list file + if not os.path.exists(ult_dlf_uri): + tools.create_file(ult_dlf_uri, tyto.ini_domains_list) + + # Ask user for domain settings + cf_load() + forms.ask_domain_title(True) + forms.ask_domain_date(True) + forms.ask_domain_about(True) + forms.ask_domain_mail(True) + forms.ask_domain_tags(True) + + # Set default lang, from config file or system lang + forms.ask_domain_lang(True) + + # Set server directory + forms.ask_domain_server(True) + + # Update Domain Configuration file + cf_update_values(True) @@ -179,35 +179,35 @@ def cf_create(): # Ask yser when default is a key form and not value # #---------------------------------------------------# def cf_set_value(section, key, default): - global new_val - try: new_val - except: new_val = False + global new_val + try: new_val + except: new_val = False + + try: + val = cf.get(section, key) + except: + try: cf.add_section(section) ; new_val = True + except: pass + val = "" + + # Values has a form + if default in tyto.keys_4q: + if val: return val + else: default = tyto.keys_questions[default](False) ; new_val = True + + # Optional key + elif not default: + if not val: return default + else: default = val + + # Force set default value + if val != default: + new_val = True - try: - val = cf.get(section, key) - except: - try: cf.add_section(section) ; new_val = True - except: pass - val = "" - - # Values has a form - if default in tyto.keys_4q: - if val: return val - else: default = tyto.keys_questions[default](False) ; new_val = True - - # Optional key - elif not default: - if not val: return default - else: default = val - - # Force set default value - if val != default: - new_val = True - - cf.set(section, key, default) - debug.out(204, "[%s] %s"%(section, key), default, False, 0, False) - - return default + cf.set(section, key, default) + debug.out(204, "[%s] %s"%(section, key), default, False, 0, False) + + return default #===========================================# @@ -216,334 +216,334 @@ def cf_set_value(section, key, default): # Ensure to set correct values # #-------------------------------------------# def cf_update_values(write): - # Load Domain Configuration file - cf_load() - - # [DOMAIN] - # ======== - global activated, title, date, about, mail, tags, license, license_url - try: activated = cf.getboolean("DOMAIN", "activated") - except: activated = cf_set_value("DOMAIN", "activated", "no") - - cf_set_value("DOMAIN", "name", name) - - title = cf_set_value("DOMAIN", "title", "title") - date = cf_set_value("DOMAIN", "date", "date") - about = cf_set_value("DOMAIN", "about", "about") - mail = cf_set_value("DOMAIN", "mail", "mail") - tags = cf_set_value("DOMAIN", "tags", "tags") - license = cf_set_value("DOMAIN", "lincese", "") - if not license: - license = cf_set_value("DOMAIN", "lincese", "gfdl-1.3") - license_url = cf_set_value("DOMAIN", "lincese_url", - "https://www.gnu.org/licenses/fdl-1.3.txt") - elif not license == "gfdl-1.3": - license_url = cf_set_value("DOMAIN", "lincese_url","") - - # Optional - global legals_url, terms_url, statuses_url - legals_url = cf_set_value("DOMAIN", "legals_url", "") - terms_url = cf_set_value("DOMAIN", "terms_url", "") - statuses_url = cf_set_value("DOMAIN", "statuses_url", "") + # Load Domain Configuration file + cf_load() + + # [DOMAIN] + # ======== + global activated, title, date, about, mail, tags, license, license_url + try: activated = cf.getboolean("DOMAIN", "activated") + except: activated = cf_set_value("DOMAIN", "activated", "no") + + cf_set_value("DOMAIN", "name", name) + + title = cf_set_value("DOMAIN", "title", "title") + date = cf_set_value("DOMAIN", "date", "date") + about = cf_set_value("DOMAIN", "about", "about") + mail = cf_set_value("DOMAIN", "mail", "mail") + tags = cf_set_value("DOMAIN", "tags", "tags") + license = cf_set_value("DOMAIN", "lincese", "") + if not license: + license = cf_set_value("DOMAIN", "lincese", "gfdl-1.3") + license_url = cf_set_value("DOMAIN", "lincese_url", + "https://www.gnu.org/licenses/fdl-1.3.txt") + elif not license == "gfdl-1.3": + license_url = cf_set_value("DOMAIN", "lincese_url","") + + # Optional + global legals_url, terms_url, statuses_url + legals_url = cf_set_value("DOMAIN", "legals_url", "") + terms_url = cf_set_value("DOMAIN", "terms_url", "") + statuses_url = cf_set_value("DOMAIN", "statuses_url", "") - - # [SERVER] - # ======== - global srv, srv_name, wip, www - srv = cf_set_value("SERVER", "root", "server") - if not tools.dir_exists(srv, False): - srv = cf_set_value("SERVER", "root", "server") - - srv_name = os.path.join(srv, name + "/") - cf_set_value("SERVER", "domain", srv_name) - - wip = os.path.join(srv_name, "wip/") - cf_set_value("SERVER", "wip", wip) - - www = os.path.join(srv_name, "www/") - cf_set_value("SERVER", "www", www) - - - # [WIP_DIRS] - # ========== - global wip_tpl, wip_images, wip_files - wip_tpl = os.path.join(wip, "template/") - cf_set_value("WIP_DIRS", "template", wip_tpl) - - wip_images = os.path.join(wip, "images/") - cf_set_value("WIP_DIRS", "images", wip_images) - - wip_files = os.path.join(wip, "files/") - cf_set_value("WIP_DIRS", "files", wip_files) - - - # [WWW_DIRS] - # ========== - global www_tpl, www_images, www_files - www_tpl = os.path.join(www, "template/") - cf_set_value("WWW_DIRS", "template", www_tpl) - - www_images = os.path.join(www, "images/") - cf_set_value("WWW_DIRS", "images", www_images) - - www_files = os.path.join(www, "files/") - cf_set_value("WWW_DIRS", "files", www_files) - - - # [WEBSITE] - # ========= - global wip_url, www_url, lang, css, sep, article_code, static - wip_url = cf_set_value("WEBSITE", "wip_url", "") - if not wip_url: - wip_url = cf_set_value("WEBSITE", "wip_url", create_wip_url()) - - www_url = cf_set_value("WEBSITE", "www_url", "") - if not www_url: - www_url = cf_set_value("WEBSITE", "www_url", "https://%s/"%name) - - lang = cf_set_value("WEBSITE", "lang", "") - if not lang: - lang = cf_set_value("WEBSITE", "lang", langs.load_website_lang()) - elif not langs.translation_exists("website", lang, False): - lang = langs.get_sys_lang() - langs.load_website_lang() - - css = cf_set_value("WEBSITE", "css", "") - if not css: - css = cf_set_value("WEBSITE", "css", "tyto") - - sep = cf_set_value("WEBSITE", "separator", "") - if not sep or len(sep) > 2: - sep = cf_set_value("WEBSITE", "separator", "|") - - try: article_code = cf.getboolean("WEBSITE", "article_code") - except: article_code = cf_set_value("WEBSITE", "article_code", "yes") - try: static = cf.getboolean("WEBSITE", "static") - except: static = cf_set_value("WEBSITE", "static", "no") - - - # [WEBSITE_MODULES] - # ================= - global navbar, sidebar_title, sidebar_items, rss_items, sitemaps - try: navbar = cf.getboolean("WEBSITE_MODULES", "navbar") - except: navbar = cf_set_value("WEBSITE_MODULES", "navbar", "yes") - - sidebar_title = cf_set_value("WEBSITE_MODULES", "sidebar_title", "") - if not sidebar_title: - sidebar_title = cf_set_value("WEBSITE_MODULES", "sidebar_title", + + # [SERVER] + # ======== + global srv, srv_name, wip, www + srv = cf_set_value("SERVER", "root", "server") + if not tools.dir_exists(srv, False): + srv = cf_set_value("SERVER", "root", "server") + + srv_name = os.path.join(srv, name + "/") + cf_set_value("SERVER", "domain", srv_name) + + wip = os.path.join(srv_name, "wip/") + cf_set_value("SERVER", "wip", wip) + + www = os.path.join(srv_name, "www/") + cf_set_value("SERVER", "www", www) + + + # [WIP_DIRS] + # ========== + global wip_tpl, wip_images, wip_files + wip_tpl = os.path.join(wip, "template/") + cf_set_value("WIP_DIRS", "template", wip_tpl) + + wip_images = os.path.join(wip, "images/") + cf_set_value("WIP_DIRS", "images", wip_images) + + wip_files = os.path.join(wip, "files/") + cf_set_value("WIP_DIRS", "files", wip_files) + + + # [WWW_DIRS] + # ========== + global www_tpl, www_images, www_files + www_tpl = os.path.join(www, "template/") + cf_set_value("WWW_DIRS", "template", www_tpl) + + www_images = os.path.join(www, "images/") + cf_set_value("WWW_DIRS", "images", www_images) + + www_files = os.path.join(www, "files/") + cf_set_value("WWW_DIRS", "files", www_files) + + + # [WEBSITE] + # ========= + global wip_url, www_url, lang, css, sep, article_code, static + wip_url = cf_set_value("WEBSITE", "wip_url", "") + if not wip_url: + wip_url = cf_set_value("WEBSITE", "wip_url", create_wip_url()) + + www_url = cf_set_value("WEBSITE", "www_url", "") + if not www_url: + www_url = cf_set_value("WEBSITE", "www_url", "https://%s/"%name) + + lang = cf_set_value("WEBSITE", "lang", "") + if not lang: + lang = cf_set_value("WEBSITE", "lang", langs.load_website_lang()) + elif not langs.translation_exists("website", lang, False): + lang = langs.get_sys_lang() + langs.load_website_lang() + + css = cf_set_value("WEBSITE", "css", "") + if not css: + css = cf_set_value("WEBSITE", "css", "tyto") + + sep = cf_set_value("WEBSITE", "separator", "") + if not sep or len(sep) > 2: + sep = cf_set_value("WEBSITE", "separator", "|") + + try: article_code = cf.getboolean("WEBSITE", "article_code") + except: article_code = cf_set_value("WEBSITE", "article_code", "yes") + try: static = cf.getboolean("WEBSITE", "static") + except: static = cf_set_value("WEBSITE", "static", "no") + + + # [WEBSITE_MODULES] + # ================= + global navbar, sidebar_title, sidebar_items, rss_items, sitemaps + try: navbar = cf.getboolean("WEBSITE_MODULES", "navbar") + except: navbar = cf_set_value("WEBSITE_MODULES", "navbar", "yes") + + sidebar_title = cf_set_value("WEBSITE_MODULES", "sidebar_title", "") + if not sidebar_title: + sidebar_title = cf_set_value("WEBSITE_MODULES", "sidebar_title", langs.site.sidebar_title) - - sidebar_items = cf_set_value("WEBSITE_MODULES", "sidebar_items", "") - if not sidebar_items or not sidebar_items.isdigit(): - sidebar_items = cf_set_value("WEBSITE_MODULES", "sidebar_items", "0") - - rss_items = cf_set_value("WEBSITE_MODULES", "rss_items", "") - if not rss_items or not rss_items.isdigit(): - rss_items = cf_set_value("WEBSITE_MODULES", "rss_items", "0") - - try: sitemaps = cf.getboolean("WEBSITE_MODULES", "sitemaps") - except: sitemaps = cf_set_value("WEBSITE_MODULES", "sitemaps", "yes") - - - # TEMPLATE_FILENAMES - # ================== - global favicon, logo, styles, rss, stats - favicon = cf_set_value("TEMPLATE_FILENAMES", "favicon", "") - if not favicon: - favicon = cf_set_value("TEMPLATE_FILENAMES", "favicon", "favicon.png") - - logo = cf_set_value("TEMPLATE_FILENAMES", "logo", "") - if not logo: - logo = cf_set_value("TEMPLATE_FILENAMES", "logo", "logo.png") - - styles = cf_set_value("TEMPLATE_FILENAMES", "styles", "") - if not styles: - styles = cf_set_value("TEMPLATE_FILENAMES", "styles", "styles.css") - - rss = cf_set_value("TEMPLATE_FILENAMES", "rss", "") - if not rss: - rss = cf_set_value("TEMPLATE_FILENAMES", "rss", "rss.xml") - - stats = cf_set_value("TEMPLATE_FILENAMES", "stats", "") - if not stats: - stats = cf_set_value("TEMPLATE_FILENAMES", "stats", "tyto_stats.ini") - - - # [USER_DIRS] - # =========== - cf_set_value("USER_DIRS", "root", wrk_dir) - cf_set_value("USER_DIRS", "articles", wrk_articles) - cf_set_value("USER_DIRS", "images", wrk_images) - cf_set_value("USER_DIRS", "files", wrk_files) - cf_set_value("USER_DIRS", "template", wrk_tpl) - cf_set_value("USER_DIRS", "modules", wrk_mods) - cf_set_value("USER_DIRS", "database", wrk_db) - - - # [USER_TEMPLATE_FILES] - # ===================== - global wrk_favicon, wrk_logo, wri_styles - wrk_favicon = os.path.join(wrk_tpl, favicon) - cf_set_value("USER_TEMPLATE_FILES", "favicon", wrk_favicon) - - wrk_logo = os.path.join(wrk_tpl, logo) - cf_set_value("USER_TEMPLATE_FILES", "logo", wrk_logo) - - wrk_styles = os.path.join(wrk_tpl, styles) - cf_set_value("USER_TEMPLATE_FILES", "styles", wrk_styles) - - - # [USER_MODULES_FILES] - # ==================== - global wrk_metas, wrk_header, wrk_navbar, wrk_sidebar, wrk_footer - wrk_metas = os.path.join(wrk_mods, "tyto_metas.raw") - cf_set_value("USER_MODULES_FILES", "metas", wrk_metas) - - wrk_header = os.path.join(wrk_mods, "tyto_header.raw") - cf_set_value("USER_MODULES_FILES", "header", wrk_header) - - wrk_navbar = os.path.join(wrk_mods, "tyto_navbar.raw") - cf_set_value("USER_MODULES_FILES", "navbar", wrk_navbar) - - wrk_sidebar = os.path.join(wrk_mods, "tyto_sidebar.raw") - cf_set_value("USER_MODULES_FILES", "sidebar", wrk_sidebar) - - wrk_footer = os.path.join(wrk_mods, "tyto_footer.raw") - cf_set_value("USER_MODULES_FILES", "footer", wrk_footer) - - - # [WIP_FILES] - # =========== - global wip_favicon, wip_logo, wip_styles, wip_rss, wip_stats - wip_favicon = os.path.join(wip_tpl, favicon) - cf_set_value("WIP_FILES", "favicon", wip_favicon) - - wip_logo = os.path.join(wip_tpl, logo) - cf_set_value("WIP_FILES", "logo", wip_logo) - - wip_styles = os.path.join(wip_tpl, styles) - cf_set_value("WIP_FILES", "styles", wip_styles) - - wip_rss = os.path.join(wip_tpl, rss) - cf_set_value("WIP_FILES", "rss", wip_rss) - - wip_stats = os.path.join(wip_tpl, stats) - cf_set_value("WIP_FILES", "stats", wip_stats) - - global wip_metas, wip_header, wip_navbar, wip_sidebar, wip_footer - wip_metas = os.path.join(wip_tpl, "metas.html") - cf_set_value("WIP_FILES", "metas", wip_metas) - - wip_header = os.path.join(wip_tpl, "header.html") - cf_set_value("WIP_FILES", "header", wip_header) - - wip_navbar = os.path.join(wip_tpl, "navbar.html") - cf_set_value("WIP_FILES", "navbar", wip_navbar) - - wip_sidebar = os.path.join(wip_tpl, "sidebar.html") - cf_set_value("WIP_FILES", "sidebar", wip_sidebar) - - wip_footer = os.path.join(wip_tpl, "footer.html") - cf_set_value("WIP_FILES", "footer", wip_footer) - - - # [WWW_FILES] - # =========== - global www_favicon, www_logo, www_styles, www_rss, www_stats - www_favicon = os.path.join(www_tpl, favicon) - cf_set_value("WWW_FILES", "favicon", www_favicon) - - www_logo = os.path.join(www_tpl, logo) - cf_set_value("WWW_FILES", "logo", www_logo) - - www_styles = os.path.join(www_tpl, styles) - cf_set_value("WWW_FILES", "styles", www_styles) - - www_rss = os.path.join(www_tpl, rss) - cf_set_value("WWW_FILES", "rss", www_rss) - - www_stats = os.path.join(www_tpl, stats) - cf_set_value("WWW_FILES", "stats", www_stats) - - global www_metas, www_header, www_navbar, www_sidebar, www_footer - www_metas = os.path.join(www_tpl, "metas.html") - cf_set_value("WWW_FILES", "metas", www_metas) - - www_header = os.path.join(www_tpl, "header.html") - cf_set_value("WWW_FILES", "header", www_header) - - www_navbar = os.path.join(www_tpl, "navbar.html") - cf_set_value("WWW_FILES", "navbar", www_navbar) - - www_sidebar = os.path.join(www_tpl, "sidebar.html") - cf_set_value("WWW_FILES", "sidebar", www_sidebar) - - www_footer = os.path.join(www_tpl, "footer.html") - cf_set_value("WWW_FILES", "footer", www_footer) - - - # [TYTO] - # ====== - cf_set_value("TYTO", "domain_hash", cf_id) - cf_set_value("TYTO", "domain_conf", cf_uri) - cf_set_value("TYTO", "domain_user", ult_cf_uri) - - - # ================================= # - # Write Configuration file # - # Only if needed or when new domain # - # --------------------------------- # - if new_val or write: - with open(cf_uri, "w") as f: - cf.write(f) - - - #=============================================# - # Update User local domain configuration file # - #---------------------------------------------# - ult_write = False - ult_cf_load() - if ult_cf.get("DOMAIN", "name") != name: - ult_cf.set("DOMAIN", "name", name) - ult_write = True - - cf_hash_c = tools.get_filesum(cf_uri, True) - if ult_cf.get("DOMAIN", "hash") != cf_hash_c: - ult_cf.set("DOMAIN", "hash", cf_hash_c) - ult_write = True - - if ult_cf.get("DOMAIN", "root") != wrk_dir: - ult_cf.set("DOMAIN", "root", wrk_dir) - ult_write = True - - if ult_cf.get("DOMAIN", "conf") != cf_uri: - ult_cf.set("DOMAIN", "conf", cf_uri) - ult_write = True - - if ult_cf.get("SERVER", "root") != srv: - ult_cf.set("SERVER", "root", srv) - ult_write = True - - if ult_write: - with open(ult_cf_uri, "w") as f: - ult_cf.write(f) - - - # Update User local Domains List File - #------------------------------------ - ult_dlf_load() - dlf_write = False - try: - dlf_line = ult_dlf.get("DOMAINS", name) - if dlf_line != wrk_dir: - dlf_write = True - except: - dlf_write = True - - if dlf_write: - ult_dlf.set("DOMAINS", name, wrk_dir) - with open(ult_dlf_uri, "w") as f: - ult_dlf.write(f) + + sidebar_items = cf_set_value("WEBSITE_MODULES", "sidebar_items", "") + if not sidebar_items or not sidebar_items.isdigit(): + sidebar_items = cf_set_value("WEBSITE_MODULES", "sidebar_items", "0") + + rss_items = cf_set_value("WEBSITE_MODULES", "rss_items", "") + if not rss_items or not rss_items.isdigit(): + rss_items = cf_set_value("WEBSITE_MODULES", "rss_items", "0") + + try: sitemaps = cf.getboolean("WEBSITE_MODULES", "sitemaps") + except: sitemaps = cf_set_value("WEBSITE_MODULES", "sitemaps", "yes") + + + # TEMPLATE_FILENAMES + # ================== + global favicon, logo, styles, rss, stats + favicon = cf_set_value("TEMPLATE_FILENAMES", "favicon", "") + if not favicon: + favicon = cf_set_value("TEMPLATE_FILENAMES", "favicon", "favicon.png") + + logo = cf_set_value("TEMPLATE_FILENAMES", "logo", "") + if not logo: + logo = cf_set_value("TEMPLATE_FILENAMES", "logo", "logo.png") + + styles = cf_set_value("TEMPLATE_FILENAMES", "styles", "") + if not styles: + styles = cf_set_value("TEMPLATE_FILENAMES", "styles", "styles.css") + + rss = cf_set_value("TEMPLATE_FILENAMES", "rss", "") + if not rss: + rss = cf_set_value("TEMPLATE_FILENAMES", "rss", "rss.xml") + + stats = cf_set_value("TEMPLATE_FILENAMES", "stats", "") + if not stats: + stats = cf_set_value("TEMPLATE_FILENAMES", "stats", "tyto_stats.ini") + + + # [USER_DIRS] + # =========== + cf_set_value("USER_DIRS", "root", wrk_dir) + cf_set_value("USER_DIRS", "articles", wrk_articles) + cf_set_value("USER_DIRS", "images", wrk_images) + cf_set_value("USER_DIRS", "files", wrk_files) + cf_set_value("USER_DIRS", "template", wrk_tpl) + cf_set_value("USER_DIRS", "modules", wrk_mods) + cf_set_value("USER_DIRS", "database", wrk_db) + + + # [USER_TEMPLATE_FILES] + # ===================== + global wrk_favicon, wrk_logo, wri_styles + wrk_favicon = os.path.join(wrk_tpl, favicon) + cf_set_value("USER_TEMPLATE_FILES", "favicon", wrk_favicon) + + wrk_logo = os.path.join(wrk_tpl, logo) + cf_set_value("USER_TEMPLATE_FILES", "logo", wrk_logo) + + wrk_styles = os.path.join(wrk_tpl, styles) + cf_set_value("USER_TEMPLATE_FILES", "styles", wrk_styles) + + + # [USER_MODULES_FILES] + # ==================== + global wrk_metas, wrk_header, wrk_navbar, wrk_sidebar, wrk_footer + wrk_metas = os.path.join(wrk_mods, "tyto_metas.raw") + cf_set_value("USER_MODULES_FILES", "metas", wrk_metas) + + wrk_header = os.path.join(wrk_mods, "tyto_header.raw") + cf_set_value("USER_MODULES_FILES", "header", wrk_header) + + wrk_navbar = os.path.join(wrk_mods, "tyto_navbar.raw") + cf_set_value("USER_MODULES_FILES", "navbar", wrk_navbar) + + wrk_sidebar = os.path.join(wrk_mods, "tyto_sidebar.raw") + cf_set_value("USER_MODULES_FILES", "sidebar", wrk_sidebar) + + wrk_footer = os.path.join(wrk_mods, "tyto_footer.raw") + cf_set_value("USER_MODULES_FILES", "footer", wrk_footer) + + + # [WIP_FILES] + # =========== + global wip_favicon, wip_logo, wip_styles, wip_rss, wip_stats + wip_favicon = os.path.join(wip_tpl, favicon) + cf_set_value("WIP_FILES", "favicon", wip_favicon) + + wip_logo = os.path.join(wip_tpl, logo) + cf_set_value("WIP_FILES", "logo", wip_logo) + + wip_styles = os.path.join(wip_tpl, styles) + cf_set_value("WIP_FILES", "styles", wip_styles) + + wip_rss = os.path.join(wip_tpl, rss) + cf_set_value("WIP_FILES", "rss", wip_rss) + + wip_stats = os.path.join(wip_tpl, stats) + cf_set_value("WIP_FILES", "stats", wip_stats) + + global wip_metas, wip_header, wip_navbar, wip_sidebar, wip_footer + wip_metas = os.path.join(wip_tpl, "metas.html") + cf_set_value("WIP_FILES", "metas", wip_metas) + + wip_header = os.path.join(wip_tpl, "header.html") + cf_set_value("WIP_FILES", "header", wip_header) + + wip_navbar = os.path.join(wip_tpl, "navbar.html") + cf_set_value("WIP_FILES", "navbar", wip_navbar) + + wip_sidebar = os.path.join(wip_tpl, "sidebar.html") + cf_set_value("WIP_FILES", "sidebar", wip_sidebar) + + wip_footer = os.path.join(wip_tpl, "footer.html") + cf_set_value("WIP_FILES", "footer", wip_footer) + + + # [WWW_FILES] + # =========== + global www_favicon, www_logo, www_styles, www_rss, www_stats + www_favicon = os.path.join(www_tpl, favicon) + cf_set_value("WWW_FILES", "favicon", www_favicon) + + www_logo = os.path.join(www_tpl, logo) + cf_set_value("WWW_FILES", "logo", www_logo) + + www_styles = os.path.join(www_tpl, styles) + cf_set_value("WWW_FILES", "styles", www_styles) + + www_rss = os.path.join(www_tpl, rss) + cf_set_value("WWW_FILES", "rss", www_rss) + + www_stats = os.path.join(www_tpl, stats) + cf_set_value("WWW_FILES", "stats", www_stats) + + global www_metas, www_header, www_navbar, www_sidebar, www_footer + www_metas = os.path.join(www_tpl, "metas.html") + cf_set_value("WWW_FILES", "metas", www_metas) + + www_header = os.path.join(www_tpl, "header.html") + cf_set_value("WWW_FILES", "header", www_header) + + www_navbar = os.path.join(www_tpl, "navbar.html") + cf_set_value("WWW_FILES", "navbar", www_navbar) + + www_sidebar = os.path.join(www_tpl, "sidebar.html") + cf_set_value("WWW_FILES", "sidebar", www_sidebar) + + www_footer = os.path.join(www_tpl, "footer.html") + cf_set_value("WWW_FILES", "footer", www_footer) + + + # [TYTO] + # ====== + cf_set_value("TYTO", "domain_hash", cf_id) + cf_set_value("TYTO", "domain_conf", cf_uri) + cf_set_value("TYTO", "domain_user", ult_cf_uri) + + + # ================================= # + # Write Configuration file # + # Only if needed or when new domain # + # --------------------------------- # + if new_val or write: + with open(cf_uri, "w") as f: + cf.write(f) + + + #=============================================# + # Update User local domain configuration file # + #---------------------------------------------# + ult_write = False + ult_cf_load() + if ult_cf.get("DOMAIN", "name") != name: + ult_cf.set("DOMAIN", "name", name) + ult_write = True + + cf_hash_c = tools.get_filesum(cf_uri, True) + if ult_cf.get("DOMAIN", "hash") != cf_hash_c: + ult_cf.set("DOMAIN", "hash", cf_hash_c) + ult_write = True + + if ult_cf.get("DOMAIN", "root") != wrk_dir: + ult_cf.set("DOMAIN", "root", wrk_dir) + ult_write = True + + if ult_cf.get("DOMAIN", "conf") != cf_uri: + ult_cf.set("DOMAIN", "conf", cf_uri) + ult_write = True + + if ult_cf.get("SERVER", "root") != srv: + ult_cf.set("SERVER", "root", srv) + ult_write = True + + if ult_write: + with open(ult_cf_uri, "w") as f: + ult_cf.write(f) + + + # Update User local Domains List File + #------------------------------------ + ult_dlf_load() + dlf_write = False + try: + dlf_line = ult_dlf.get("DOMAINS", name) + if dlf_line != wrk_dir: + dlf_write = True + except: + dlf_write = True + + if dlf_write: + ult_dlf.set("DOMAINS", name, wrk_dir) + with open(ult_dlf_uri, "w") as f: + ult_dlf.write(f) #========================================# @@ -552,19 +552,18 @@ def cf_update_values(write): # if activated, check/create wrk dirs # #----------------------------------------# def userset_status(action): - - do = { + do = { "start" : "yes", "stop" : "no" } - - tools.update_ini_file(cf_uri, "DOMAIN", "activated", do[action]) - cf_update_values(False) - ready() - - if action == "start": - status = cf.get("DOMAIN", "activated") - debug.out(209, "[DOMAIN] activated = %s"%status, cf_uri, True, 0, False) + + tools.update_ini_file(cf_uri, "DOMAIN", "activated", do[action]) + cf_update_values(False) + ready() + + if action == "start": + status = cf.get("DOMAIN", "activated") + debug.out(209, "[DOMAIN] activated = %s"%status, cf_uri, True, 0, False) #========================================# @@ -574,12 +573,12 @@ def userset_status(action): # or check/create wrk directories # #----------------------------------------# def ready(): - if not activated: - status = cf.get("DOMAIN", "activated") - debug.out(105, "[DOMAIN] activated = %s"%status, cf_uri, True, 1, True) - - for key, directory in cf.items("USER_DIRS"): - tools.create_dirs(directory) + if not activated: + status = cf.get("DOMAIN", "activated") + debug.out(105, "[DOMAIN] activated = %s"%status, cf_uri, True, 1, True) + + for key, directory in cf.items("USER_DIRS"): + tools.create_dirs(directory) #======#======================================================================= @@ -590,10 +589,10 @@ def ready(): # Exit Tyto if in black hole... # #-----------------------------------# try: - user_dir = os.getcwd() + "/" - home_dir = os.path.expanduser('~') + user_dir = os.getcwd() + "/" + home_dir = os.path.expanduser('~') except: - debug.out(2, "PWD", "?", True, 2, True) + debug.out(2, "PWD", "?", True, 2, True) #======# diff --git a/src/var/lib/tyto/program/forms.py b/src/var/lib/tyto/program/forms.py index 80fb03d..09df2fb 100644 --- a/src/var/lib/tyto/program/forms.py +++ b/src/var/lib/tyto/program/forms.py @@ -43,7 +43,7 @@ import debug, domain, langs, tools # user interrupts... # #--------------------# def maybe_later(expected, answer): - debug.out(255, expected, answer, True, 0, True) + debug.out(255, expected, answer, True, 0, True) #=========================# @@ -51,29 +51,29 @@ def maybe_later(expected, answer): # yes_only : True / False # #-------------------------# def ask(q, yes_only, default): - expected = "" - if yes_only: - expected = langs.logs.ok - - try: answer = input(q) - except KeyboardInterrupt: print("") ; maybe_later(expected, "?") - - # return default answer if exists - if not answer: - if default: - return default + expected = "" + if yes_only: + expected = langs.logs.ok + + try: answer = input(q) + except KeyboardInterrupt: print("") ; maybe_later(expected, "?") + + # return default answer if exists + if not answer: + if default: + return default - maybe_later(expected, "?") - - # Answer is a Y/N process - if yes_only: - for ok in langs.logs.ok: - if answer.lower() == ok.lower(): - return True + maybe_later(expected, "?") + + # Answer is a Y/N process + if yes_only: + for ok in langs.logs.ok: + if answer.lower() == ok.lower(): + return True - maybe_later(expected, answer) - - return answer + maybe_later(expected, answer) + + return answer #====================================# @@ -81,11 +81,11 @@ def ask(q, yes_only, default): # return value[0:12] # #------------------------------------# def shorter(value): - if len(value) > 12: - return '%s...'%(value[0:12]) - - # Or legacy - return value + if len(value) > 12: + return '%s...'%(value[0:12]) + + # Or legacy + return value #=========================# @@ -93,8 +93,8 @@ def shorter(value): # from directory basename # # ------------------------# def ask_domain_shortname(config_name): - q = "> %s (%s)%s "%(langs.logs.configure_domain, config_name, langs.logs.q) - ask(q, True, False) + q = "> %s (%s)%s "%(langs.logs.configure_domain, config_name, langs.logs.q) + ask(q, True, False) #=======================# @@ -104,14 +104,14 @@ def ask_domain_shortname(config_name): # - False: return value # #-----------------------# def ask_domain_title(update): - try: title = domain.cf.get("DOMAIN", "title") - except: title = "" - - q = "> %s (%s)%s "%(langs.logs.domain_title, shorter(title), langs.logs.q) - answer = ask(q, False, title) - - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "title", answer) - else: return answer + try: title = domain.cf.get("DOMAIN", "title") + except: title = "" + + q = "> %s (%s)%s "%(langs.logs.domain_title, shorter(title), langs.logs.q) + answer = ask(q, False, title) + + if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "title", answer) + else: return answer #===========================# @@ -122,24 +122,24 @@ def ask_domain_title(update): # - False: return value # #---------------------------# def ask_domain_date(update): - try: date = domain.cf.get("DOMAIN", "date") - except: date = "YYYY[-MM][-DD]" - - example = date - - q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q) - answer = ask(q, False, date) - - # Check date format (not valid date) - try: - parse(answer) - except: - debug.out(50, "YYYY[-MM-DD]", answer, True, 2, False) - ask_domain_date(update) - return - - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "date", answer) - else: return answer + try: date = domain.cf.get("DOMAIN", "date") + except: date = "YYYY[-MM][-DD]" + + example = date + + q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q) + answer = ask(q, False, date) + + # Check date format (not valid date) + try: + parse(answer) + except: + debug.out(50, "YYYY[-MM-DD]", answer, True, 2, False) + ask_domain_date(update) + return + + if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "date", answer) + else: return answer #========================# @@ -149,14 +149,14 @@ def ask_domain_date(update): # - False: return value # #------------------------# def ask_domain_about(update): - try: about = domain.cf.get("DOMAIN", "about") - except: about = "" - - q = "> %s (%s)%s "%(langs.logs.domain_about, shorter(about), langs.logs.q) - answer = ask(q, False, about) - - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "about", answer) - else: return answer + try: about = domain.cf.get("DOMAIN", "about") + except: about = "" + + q = "> %s (%s)%s "%(langs.logs.domain_about, shorter(about), langs.logs.q) + answer = ask(q, False, about) + + if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "about", answer) + else: return answer #=======================# @@ -166,14 +166,14 @@ def ask_domain_about(update): # - False: return value # #-----------------------# def ask_domain_mail(update): - try: mail = domain.cf.get("DOMAIN", "mail") - except: mail = "" - - q = "> %s (%s)%s "%(langs.logs.domain_mail, shorter(mail), langs.logs.q) - answer = ask(q, False, mail) - - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "mail", answer) - else: return answer + try: mail = domain.cf.get("DOMAIN", "mail") + except: mail = "" + + q = "> %s (%s)%s "%(langs.logs.domain_mail, shorter(mail), langs.logs.q) + answer = ask(q, False, mail) + + if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "mail", answer) + else: return answer #===============================================# @@ -183,22 +183,22 @@ def ask_domain_mail(update): # - False: return value # #-----------------------------------------------# def ask_domain_tags(update): - try: tags = domain.cf.get("DOMAIN", "tags") - except: tags = "" - - q = "> %s (%s)%s "%(langs.logs.domain_tags, shorter(tags), langs.logs.q) - answer = ask(q, False, tags) - - # Remove useless spaces for HTML meta - tuple_tags = answer.rsplit(",") - answer = "" - for i, tag in enumerate(tuple_tags): - answer = answer + tag.strip() - if i != len(tuple_tags) - 1: - answer = answer + "," - - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "tags", answer) - else: return answer + try: tags = domain.cf.get("DOMAIN", "tags") + except: tags = "" + + q = "> %s (%s)%s "%(langs.logs.domain_tags, shorter(tags), langs.logs.q) + answer = ask(q, False, tags) + + # Remove useless spaces for HTML meta + tuple_tags = answer.rsplit(",") + answer = "" + for i, tag in enumerate(tuple_tags): + answer = answer + tag.strip() + if i != len(tuple_tags) - 1: + answer = answer + "," + + if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "tags", answer) + else: return answer #===================================# @@ -206,52 +206,52 @@ def ask_domain_tags(update): # default en if no translation file # > !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! < TODO #-----------------------------------# def ask_domain_lang(update): - try: lang = domain.cf.get("WEBSITE", "lang") or langs.get_sys_lang() - except: lang = "" - - - q = "> %s (%s)%s "%(langs.logs.domain_lang, lang, langs.logs.q) - answer = ask(q, False, lang).lower() - - # Lang Format is 2 character - if len(answer) != 2: - debug.out("8", "xx", answer, True, 2, False) - debug.out(103, "en", "%swebsite_en.py"%langs.trfs, True, 1, False) - answer = lang - - # Check if translation file exists - if not langs.translation_exists("website", answer, False): - lang = lang.get_sys_lang() - debug.out(103, lang, "%swebsite_%s.py"%(langs.trfs, lang), True, 1, False) - answer = lang - - if update: tools.update_ini_file(domain.cf_uri, "WEBSITE", "lang", answer) - else: return lang + try: lang = domain.cf.get("WEBSITE", "lang") or langs.get_sys_lang() + except: lang = "" + + + q = "> %s (%s)%s "%(langs.logs.domain_lang, lang, langs.logs.q) + answer = ask(q, False, lang).lower() + + # Lang Format is 2 character + if len(answer) != 2: + debug.out("8", "xx", answer, True, 2, False) + debug.out(103, "en", "%swebsite_en.py"%langs.trfs, True, 1, False) + answer = lang + + # Check if translation file exists + if not langs.translation_exists("website", answer, False): + lang = lang.get_sys_lang() + debug.out(103, lang, "%swebsite_%s.py"%(langs.trfs, lang), True, 1, False) + answer = lang + + if update: tools.update_ini_file(domain.cf_uri, "WEBSITE", "lang", answer) + else: return lang #===================================# # Get domain server root # #-----------------------------------# def ask_domain_server(update): - try: - srv = domain.cf.get("SERVER", "root") - if not tools.dir_exists(srv, False): + try: + srv = domain.cf.get("SERVER", "root") + if not tools.dir_exists(srv, False): + srv = "" + except: srv = "" - except: - srv = "" - - if srv and not tools.dir_exists(srv, False): - srv = "" - - q = "> %s (%s)%s "%(langs.logs.domain_srv, srv, langs.logs.q) - answer = ask(q, False, srv) - - # Check if directory exists - if not tools.dir_exists(answer, False): - answer = "" - ask_domain_server(update) - return - - if update: tools.update_ini_file(domain.cf_uri, "SERVER", "root", answer) - else: return answer + + if srv and not tools.dir_exists(srv, False): + srv = "" + + q = "> %s (%s)%s "%(langs.logs.domain_srv, srv, langs.logs.q) + answer = ask(q, False, srv) + + # Check if directory exists + if not tools.dir_exists(answer, False): + answer = "" + ask_domain_server(update) + return + + if update: tools.update_ini_file(domain.cf_uri, "SERVER", "root", answer) + else: return answer diff --git a/src/var/lib/tyto/program/help.py b/src/var/lib/tyto/program/help.py index fbddfc3..d29a830 100644 --- a/src/var/lib/tyto/program/help.py +++ b/src/var/lib/tyto/program/help.py @@ -40,4 +40,4 @@ import langs, debug # Help Contents is in translations/logs_XX # #------------------------------------------# def show(action, target): - print(langs.logs.help_contents) + print(langs.logs.help_contents) diff --git a/src/var/lib/tyto/program/langs.py b/src/var/lib/tyto/program/langs.py index 0dc4aba..be4b326 100644 --- a/src/var/lib/tyto/program/langs.py +++ b/src/var/lib/tyto/program/langs.py @@ -49,17 +49,20 @@ trfs = "/var/lib/tyto/translations/" # return True or False # #----------------------------------# def translation_exists(module, lang, out): - global tr_file - - modules = ("logs", "website") - if not module in modules: return # in case of internal typo error - - tr_file = "%s%s_%s.py"%(trfs, module, lang) - if not os.path.exists(tr_file): - debug.out(5, lang, tr_file, True, 2, False) - return False - - return True + global tr_file + + modules = ("logs", "website") + # in case of internal typo error + if not module in modules: + print("! langs: internal error: 'logs', 'website'") + sys.exit(254) + + tr_file = "%s%s_%s.py"%(trfs, module, lang) + if not os.path.exists(tr_file): + debug.out(5, lang, tr_file, True, 2, False) + return False + + return True #=============================================================================# @@ -70,33 +73,33 @@ def translation_exists(module, lang, out): # Get system Lang to set logs # #-----------------------------# def get_sys_lang(): - global lang, tr_logs_uri - - tr_logs_uri = "%slogs_%s.py" - - try: lang = locale.getdefaultlocale()[0].rsplit("_")[0] - except: lang = "en" - - if not translation_exists("logs", lang, False): - lang = "en" - - tr_logs_uri = tr_logs_uri%(trfs, lang) - - return lang + global lang, tr_logs_uri + + tr_logs_uri = "%slogs_%s.py" + + try: lang = locale.getdefaultlocale()[0].rsplit("_")[0] + except: lang = "en" + + if not translation_exists("logs", lang, False): + lang = "en" + + tr_logs_uri = tr_logs_uri%(trfs, lang) + + return lang #===============================# # Import logs lang file in logs # #-------------------------------# def load_logs_lang(): - global logs, lang, set_logs - - try: - set_logs - except: - logs = __import__("logs_%s"%get_sys_lang()) - debug.out(201, lang, tr_logs_uri, False, 0, False) - set_logs = True + global logs, lang, set_logs + + try: + set_logs + except: + logs = __import__("logs_%s"%get_sys_lang()) + debug.out(201, lang, tr_logs_uri, False, 0, False) + set_logs = True #=============================================================================# @@ -107,30 +110,31 @@ def load_logs_lang(): # Get website lang from cf to set site # #---------------------------------------# def get_website_lang(): - global site_lang, tr_website_uri - - tr_website_uri = "%swebsite_%s.py" - try: site_lang = domain.cf.get("WEBSITE", "lang") - except: site_lang = get_sys_lang() - - if not translation_exists("website", site_lang, False): - site_lang = get_sys_lang() # or default "en" - - tr_website_uri = tr_website_uri%(trfs, site_lang) - - return site_lang + global site_lang, tr_website_uri + + tr_website_uri = "%swebsite_%s.py" + try: site_lang = domain.cf.get("WEBSITE", "lang") + except: site_lang = get_sys_lang() + + if not translation_exists("website", site_lang, False): + site_lang = get_sys_lang() # or default "en" + + tr_website_uri = tr_website_uri%(trfs, site_lang) + + return site_lang #==================================# # Import website lang file in site # #----------------------------------# def load_website_lang(): - global site, site_lang, set_site - - site = __import__("website_%s"%get_website_lang()) - - try: - set_site - except: - debug.out(208, site_lang, tr_website_uri, False, 0, False) - set_site = True + global site, site_lang, set_site + + site = __import__("website_%s"%get_website_lang()) + + try: + set_site + except: + debug.out(208, site_lang, tr_website_uri, False, 0, False) + set_site = True + diff --git a/src/var/lib/tyto/program/new.py b/src/var/lib/tyto/program/new.py index 58d141c..d8b6141 100644 --- a/src/var/lib/tyto/program/new.py +++ b/src/var/lib/tyto/program/new.py @@ -40,11 +40,11 @@ import args, domain # Specific to action "new" # #------------------------------------# def manage(action, target): - do = { - "domain" : create_domain, - } - - do[target]() + do = { + "domain" : create_domain, + } + + do[target]() @@ -54,8 +54,8 @@ def manage(action, target): # or if user "force" option #-----------------------------------# def create_domain(): - if not domain.cf_exists() or args.force: - domain.cf_create() - return + if not domain.cf_exists() or args.force: + domain.cf_create() + return diff --git a/src/var/lib/tyto/program/post.py b/src/var/lib/tyto/program/post.py index f75cbc6..b009313 100644 --- a/src/var/lib/tyto/program/post.py +++ b/src/var/lib/tyto/program/post.py @@ -46,43 +46,43 @@ error = 0 # load database # #--------------------------------------------# def is_article(target): - # User MUST be in articles/ - domain.user_dir.startswith(domain.wrk_articles) or \ - debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True) - - # Target URI most be from legacy directory or not begins with - if target.startswith(tyto.notarget): - error = debug.out(20, "./, ../", target, True, 2, False) - return False - - # Article exists - global uri - uri = os.path.join(domain.wrk_articles, target) - if not os.path.exists(uri): - error = debug.out(5, "False", uri, True, 2, False) - return False - - # Article is a Tyto format and not empty (exit on errors) - if not is_tyto_format(): - return False - - global uri_id, wrk_id, cf_uri, wrk_target - # Set post ID from... - uri_id = tools.get_filesum(uri, False) # ...URI - wrk_id = tools.get_filesum(uri, True) # ...CONTENTS - - # Set post configuration file database - cf_uri = os.path.join(domain.wrk_db, uri_id + ".ini") - - # Set target from articles/ - wrk_target = uri.rsplit(domain.wrk_articles)[1] - - # Load Database - global db - db = False - db = cf_load() # True or False - - return True + # User MUST be in articles/ + domain.user_dir.startswith(domain.wrk_articles) or \ + debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True) + + # Target URI most be from legacy directory or not begins with + if target.startswith(tyto.notarget): + error = debug.out(20, "./, ../", target, True, 2, False) + return False + + # Article exists + global uri + uri = os.path.join(domain.wrk_articles, target) + if not os.path.exists(uri): + error = debug.out(5, "False", uri, True, 2, False) + return False + + # Article is a Tyto format and not empty (exit on errors) + if not is_tyto_format(): + return False + + global uri_id, wrk_id, cf_uri, wrk_target + # Set post ID from... + uri_id = tools.get_filesum(uri, False) # ...URI + wrk_id = tools.get_filesum(uri, True) # ...CONTENTS + + # Set post configuration file database + cf_uri = os.path.join(domain.wrk_db, uri_id + ".ini") + + # Set target from articles/ + wrk_target = uri.rsplit(domain.wrk_articles)[1] + + # Load Database + global db + db = False + db = cf_load() # True or False + + return True #=========================================# @@ -90,33 +90,33 @@ def is_article(target): # Return True or False # #-----------------------------------------# def is_tyto_format(): - global head_contents, text_contents, contents - global head_lines, text_lines, lines - - head_contents = text_contents = "" - - with open(uri, "r") as contents: - contents = contents.read() - try: - head_contents = contents.rsplit(sep)[0] - text_contents = contents.rsplit(sep)[1] - except: - error = debug.out(21, sep, uri, True, 2, False) + global head_contents, text_contents, contents + global head_lines, text_lines, lines + + head_contents = text_contents = "" + + with open(uri, "r") as contents: + contents = contents.read() + try: + head_contents = contents.rsplit(sep)[0] + text_contents = contents.rsplit(sep)[1] + except: + error = debug.out(21, sep, uri, True, 2, False) + return False + + if not head_contents: + error = debug.out(22, "?", uri, True, 2, False) return False - - if not head_contents: - error = debug.out(22, "?", uri, True, 2, False) - return False - - if not text_contents: - error = debug.out(23, "?", uri, True, 2, False) - return False - - lines = len(contents.splitlines()) - head_lines = len(head_contents.splitlines()) - text_lines = len(text_contents.splitlines()) - - return True + + if not text_contents: + error = debug.out(23, "?", uri, True, 2, False) + return False + + lines = len(contents.splitlines()) + head_lines = len(head_contents.splitlines()) + text_lines = len(text_contents.splitlines()) + + return True #=======================================# @@ -124,32 +124,58 @@ def is_tyto_format(): # return True, or False if unused (yet) # #---------------------------------------# def cf_load(): - global cf - cf = False - - if not os.path.exists(cf_uri): - tools.create_file(cf_uri, ini_template) - - cf = configparser.ConfigParser() - cf.read(cf_uri) - - return True + global cf + cf = False + + os.path.exists(cf_uri) or tools.create_file(cf_uri, ini_template) + + cf = configparser.ConfigParser() + cf.read(cf_uri) + + return True #====================================================# # Check if post database configuration file is valid # #----------------------------------------------------# def cf_valid(): - global chk_hash, wip_hash, www_hash - - chk_hash = cf.get("CHECK", "hash") - wip_hash = cf.get("WIP", "hash") - www_hash = cf.get("WWW", "hash") + global chk_hash, wip_hash, www_hash + + chk_hash = cf.get("CHECK", "hash") + wip_hash = cf.get("WIP", "hash") + www_hash = cf.get("WWW", "hash") #======# # MAIN #======================================================================= #======# +# Statistics +# ========== +stats_tyto_head_coms = 0 +stats_tyto_text_coms = 0 +stats_html_coms = 0 +stats_titles = 0 +stats_bcodes = 0 +stats_quotes = 0 +stats_parags = 0 +stats_links = 0 +stats_images = 0 +stats_files = 0 +stats_raws = 0 +stats_codes = 0 +stats_abbrs = 0 +stats_codes = 0 +stats_raws = 0 + +stats_total_files = 0 + +stats_text_links = 0 +stats_text_files = 0 +stats_text_images = 0 +stats_text_abbrs = 0 +stats_text_codes = 0 +stats_text_raws = 0 + # head_contents #============== @@ -170,16 +196,26 @@ author = ("author:", False) logo = ("logo:", False) # Multiple lines (3) -ml_tags = ("link:", "image:", "file:", "raw:", "code:", "abbr:") -ml_marks = { - "link:" : "__", - "file:" : "--", - "image:" : "_image:", - "abbr:" : "::" - } +ml_tags = ("link:", "image:", "file:", "raw:", "code:", "abbr:") +ml_tags_marks = { + "link:" : "__", + "file:" : "--", + "image:" : "_image:", + "abbr:" : "::", + "raw:" : "_raw:", + "code:" : "_code:" + } +ml_tags_stats = { + "link:" : stats_links, + "file:" : stats_files, + "image:" : stats_images, + "abbr:" : stats_abbrs, + "raw:" : stats_raws, + "code:" : stats_codes, + } # Markers with uri in value2 -value2s_uri = (ml_tags[1], ml_tags[2], ml_tags[3]) +value2s_uri = (ml_tags[1], ml_tags[2], ml_tags[3], ml_tags[4]) value2s_ext_uris = ("http", "ftp") # text_contents @@ -194,41 +230,17 @@ raw_contents = ("bcodes", "quotes") # Comments text_comments = (";;", "" } # Tyto Titles #1 =

    tyto_titles = ("#1", "#2", "#3", "#4", "#5") html_titles = { - "#1" : '

    %s', - "#2" : '

    %s

    ', - "#3" : '

    %s

    ', - "#4" : '
    %s
    ', - "#5" : '
    %s
    ', + "#1" : '

    %s

    ', + "#2" : '

    %s

    ', + "#3" : '

    %s

    ', + "#4" : '
    %s
    ', + "#5" : '
    %s
    ', } -# Statistics -# ========== -stats_tyto_head_coms = 0 -stats_tyto_text_coms = 0 -stats_html_coms = 0 -stats_titles = 0 -stats_bcodes = 0 -stats_quotes = 0 -stats_parags = 0 -stats_links = 0 -stats_images = 0 -stats_files = 0 -stats_raws = 0 -stats_codes = 0 -stats_abbrs = 0 - -stats_total_files = 0 - -stats_text_links = 0 -stats_text_files = 0 -stats_text_images = 0 -stats_text_abbrs = 0 - #=============================# # articles configuration file # @@ -245,6 +257,10 @@ ini_template = """[DOMAIN] [WWW] +[COMMENTS] + +[TITLES] + [LINKS] [FILES] @@ -264,5 +280,4 @@ ini_template = """[DOMAIN] [STATS_HEADERS] [STATS_TEXTS] - """ diff --git a/src/var/lib/tyto/program/show.py b/src/var/lib/tyto/program/show.py index ee4c051..ee3f698 100644 --- a/src/var/lib/tyto/program/show.py +++ b/src/var/lib/tyto/program/show.py @@ -41,25 +41,25 @@ import domain, debug # Specific to action "show" # #------------------------------------# def manage(action, target): - do = { - "domains": all_domains, - } - - do[target]() + do = { + "domains": all_domains, + } + + do[target]() #============================# # List all registred domains # #----------------------------# def all_domains(): - domain.ult_dlf_load() - try: - c = 0 - for key, value in domain.ult_dlf.items("DOMAINS"): - if key: c += 1 - print(": %s > %s"%(key,value)) - print("|\n; total =",c) - - except: - debug.out(104, "False", domain.ult_dlf_uri, True, 1, False) + domain.ult_dlf_load() + try: + c = 0 + for key, value in domain.ult_dlf.items("DOMAINS"): + if key: c += 1 + print(": %s > %s"%(key,value)) + print("|\n; total =",c) + + except: + debug.out(104, "False", domain.ult_dlf_uri, True, 1, False) diff --git a/src/var/lib/tyto/program/tools.py b/src/var/lib/tyto/program/tools.py index e750bdc..77e7757 100644 --- a/src/var/lib/tyto/program/tools.py +++ b/src/var/lib/tyto/program/tools.py @@ -33,7 +33,7 @@ #-------------------------- from hashlib import blake2b -import sys, os, configparser, datetime, time +import sys, os, configparser, datetime, time, base64 import debug, domain @@ -41,17 +41,17 @@ import debug, domain # # def exit(targets, error): - if targets: return - - sys.exit(error) + if targets: return + + sys.exit(error) #==============================# # Set and return date and time # #------------------------------# def nowdate(): - now = datetime.datetime.now() - return(now.strftime('%Y-%m-%d %H:%M:%S')) + now = datetime.datetime.now() + return(now.strftime('%Y-%m-%d %H:%M:%S')) # @@ -59,18 +59,18 @@ def nowdate(): # Return date (only year) for post database # def local_date(date): - date = date.rsplit(" ")[0] # if nowdate() - - year = date.rsplit("-")[0] - month = date.rsplit("-")[1] - day = date.rsplit("-")[2] - - dates = { - "fr" : "%s/%s/%s"%(day, month, year), - "en" : date, - } - - return dates[domain.lang] + date = date.rsplit(" ")[0] # if nowdate() + + year = date.rsplit("-")[0] + month = date.rsplit("-")[1] + day = date.rsplit("-")[2] + + dates = { + "fr" : "%s/%s/%s"%(day, month, year), + "en" : date, + } + + return dates[domain.lang] #========================# @@ -79,12 +79,12 @@ def local_date(date): # False = URI # #------------------------# def get_filesum(path, src): - file_sum = blake2b(digest_size=4) - - if src: file_sum.update(open(path, 'rb').read()) - else: file_sum.update(path.encode()) - - return file_sum.hexdigest() + file_sum = blake2b(digest_size=4) + + if src: file_sum.update(open(path, 'rb').read()) + else: file_sum.update(path.encode()) + + return file_sum.hexdigest() #========================================# @@ -92,66 +92,102 @@ def get_filesum(path, src): # Mainly used to check domain server dir # #----------------------------------------# def dir_exists(dir_path, out): - if not bool(os.path.exists(dir_path)): - debug.out(6, "False", dir_path, out, 2, out) - return False - - return True + if not bool(os.path.exists(dir_path)): + debug.out(6, "False", dir_path, out, 2, out) + return False + + return True #====================# # Create directories # #--------------------# def create_dirs(path): - try: - if not os.path.exists(path): - os.makedirs(path, exist_ok=True) - debug.out(203, "True", path, False, 0, False) - except: - # Exit if not created - debug.out(5, "False", path, True, 2, True) + try: + if not os.path.exists(path): + os.makedirs(path, exist_ok=True) + debug.out(203, "True", path, False, 0, False) + except: + # Exit if not created + debug.out(5, "False", path, True, 2, True) #============================# # Create a new file and logs # #----------------------------# def create_file(file_path, contents): - up = bool(os.path.exists(file_path)) - - try: - with open(file_path, "w") as f: - f.write(contents) - except: - # Exit at error - debug.out(7, "False", file_path, True, 2, True) - - # log "update" or "new" - file_name = os.path.basename(file_path) - if up: debug.out(207, file_name, file_path, False, 0, False) - else: debug.out(206, file_name, file_path, False, 0, False) + up = bool(os.path.exists(file_path)) + + try: + with open(file_path, "w") as f: + f.write(contents) + except: + # Exit at error + debug.out(7, "False", file_path, True, 2, True) + + # log "update" or "new" + file_name = os.path.basename(file_path) + if up: debug.out(207, file_name, file_path, False, 0, False) + else: debug.out(206, file_name, file_path, False, 0, False) #===========================================# # Update ini file, replacing existing value # #-------------------------------------------# def update_ini_file(file_path, section, key, val): - # Exit if no file - if not os.path.exists(file_path): - debug.out(5, "False", file_path, True, 2, True) + # Exit if no file + if not os.path.exists(file_path): + debug.out(5, "False", file_path, True, 2, True) + + # Load ini file + config = configparser.ConfigParser() + config.read(file_path) + + # New value is same as registred + try: + if config.get(section, key) == val: + return + except: + config.add_section(section) + + # Update file with new value + config.set(section, key, val) + with open(file_path, "w") as f: + config.write(f) - # Load ini file - config = configparser.ConfigParser() - config.read(file_path) - - # New value is same as registred - try: - if config.get(section, key) == val: - return - except: - config.add_section(section) - - # Update file with new value - config.set(section, key, val) - with open(file_path, "w") as f: - config.write(f) +#====================# +# Base64 Convertions # +#--------------------# +def b64_convert(action, content): + if action == 'encode': + global b64_content + + b64_base64 = '' + content_bytes = content.encode("utf8") + base64_bytes = base64.b64encode(content_bytes) + b64_content = base64_bytes.decode("utf8") + return b64_content + + elif action == 'decode': + global src_content + + src_content = '' + content_bytes = content.encode("utf8") + base64_bytes = base64.b64decode(content_bytes) + src_content = base64_bytes.decode("utf8") + return src_content + + +#================================# +# Convert html sign in string # +# used to deactivate HTML markup # +# Return new string # +#--------------------------------# +def convert_html_signs(string): + string = string.replace('<', '<') + string = string.replace('>', '>') + astring = string.replace('"', '"') + string = string.replace("'", ''') + + return string diff --git a/src/var/lib/tyto/program/tyto.py b/src/var/lib/tyto/program/tyto.py index a16c480..70a38e8 100644 --- a/src/var/lib/tyto/program/tyto.py +++ b/src/var/lib/tyto/program/tyto.py @@ -93,3 +93,14 @@ ini_domains_list = """[DOMAINS] # Put here values where posts target cannot begin with notarget = ("./", "../") + +#======# +# HTML #======================================================================= +#======# +pre_bcode = """
    +
    +
      +%s +
    +
    +
    """ diff --git a/src/var/lib/tyto/program/userset.py b/src/var/lib/tyto/program/userset.py index bd23470..e08b000 100644 --- a/src/var/lib/tyto/program/userset.py +++ b/src/var/lib/tyto/program/userset.py @@ -40,22 +40,21 @@ import langs, forms, domain # Specific to action "set # #------------------------------------# def manage(action, target): - # Load or Exit if no configuration - domain.cf_load() - - if action == "set": - do = { - "title" : forms.ask_domain_title, - "date" : forms.ask_domain_date, - "about" : forms.ask_domain_about, - "mail" : forms.ask_domain_mail, - "lang" : forms.ask_domain_lang, - "server" : forms.ask_domain_server, - } + # Load or Exit if no configuration + domain.cf_load() + + if action == "set": + do = { + "title" : forms.ask_domain_title, + "date" : forms.ask_domain_date, + "about" : forms.ask_domain_about, + "mail" : forms.ask_domain_mail, + "lang" : forms.ask_domain_lang, + "server" : forms.ask_domain_server, + } - do[target](True) - - elif action in ("start", "stop") and target == "domain": - domain.userset_status(action) - + do[target](True) + + elif action in ("start", "stop") and target == "domain": + domain.userset_status(action)