PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/backups/cpanel_plugin
Viewing File: /opt/backups/cpanel_plugin/backup_mgr.js
// vim: set sw=4 ts=4 et /* check for ongoing restores and display them; if there are onoing restores, * set a timer for update_countdown */ function update_restore_queues() { do_post('get_restores', {}, function(data) { // reset the timer var countdown_span = $j('#restore_queue_timer'); countdown_span.data('timer', countdown_span.data('dur')); if (data.status != 0) { console.log(data); $j('#loading-div').data('restores-loaded', 1); finish_loading(); return; } var do_timer = false; // whether to start the refresh timer var has_queue = false; // if items appear in the "Restorations In Queue" col var queue_div = $j('#restore_queue'); queue_div.empty(); $j.each(data.data, function(restore_index, restore) { has_queue = true; if (restore.state == 'In Progress' || restore.state == 'Starting') { do_timer = true; } queue_div.append(make_restore_div(restore)); }); if (has_queue) { $j('#restore_queue_div').show(); } else { $j('#restore_queue_div').hide(); } if (do_timer) { $j('#restore_queue_timer_div').show(); if (window.countdown_timer == undefined) { window.countdown_timer = setInterval(update_countdown, 1000); } } else { $j('#restore_queue_timer_div').hide(); } $j('#loading-div').data('restores-loaded', 1); finish_loading(); }); } /* decrement the restore queue countdown until 0, then stop the timer * and run update_restore_queues again */ function update_countdown() { var span = $j('#restore_queue_timer'); var num = Number(span.data('timer')); if (num > 1) { span.data('timer', num - 1); } else { span.text('timer', 0); // update_restore_queues will start the timer again if needed clearInterval(window.countdown_timer); window.countdown_timer = undefined; update_restore_queues(); } } /* make an individual div.well for the restoration queues */ function make_restore_div(restore) { // Make the progress bar var progbar = $j('<div>', { 'class': 'progress restore-progress' }); if (restore.state == 'Failed') { var progbar_inner = $j('<div>', { 'class': 'progress-bar restore-progress-failed' }); progbar_inner.css('width', '100%'); } else if (restore.state == 'Finished') { var progbar_inner = $j('<div>', { 'class': 'progress-bar restore-progress-finished' }); progbar_inner.css('width', '100%'); } else { var progbar_inner = $j('<div>', { 'class': 'progress-bar bar-animated' }); progbar_inner.css('width', String(restore.progress).concat('%')); } if (restore.state == 'Failed' || restore.state == 'Finished') { progbar.append($j('<span>', { 'text': restore.state, 'class': 'restore-prog-span-done' })); } else { progbar.append($j('<span>', { 'text': restore.state, 'class': 'restore-prog-span' })); } progbar.append(progbar_inner); // Make the cancel link var cancel_btn = $j('<a>', { href: '#', onClick: 'cancel_restore_item(this)' }); cancel_btn.data('tag', restore.tag); if (restore.state == 'Finished') { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': '&nbsp;Dismiss' })); } else if (restore.state == 'Failed') { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': '&nbsp;Delete' })); } else { cancel_btn.append($j('<i>', { 'class': 'fa fa-trash', 'html': '&nbsp;Cancel' })); } var top = $j('<div>', { 'class': 'row' }); var title = ''.concat(restore.task) .concat(' Restoration from ') .concat(stamp_to_human(restore.time, false)); top.append($j('<strong>', { 'text': title, 'class': 'col-sm-4' })); var progbar_col = $j('<div>', { 'class': 'col-sm-8' }); progbar_col.append(progbar); top.append(progbar_col); var bottom = $j('<div>', { 'class': 'row' }); bottom.append($j('<div>', { 'text': restore.restoring, 'class': 'col-sm-4' })); var btn_grp = $j('<div>', { 'class': 'col-sm-4 restore-item-btns' }); var ticket_area = $j('<div>', { 'class': 'col-sm-4 ticket-submit' }); ticket_area.data('tag', restore.tag); // If this is a failed task, more buttons if (restore.state == 'Failed') { // Make the log button var log_btn = $j('<a>', { href: '#', onClick: 'view_fail_log(this)' }); log_btn.append($j('<i>', { 'class': 'fa fa-book', 'html': '&nbsp;View&nbsp;Fail&nbsp;Log' })); log_btn.data('log', restore.log); // Button to make a ticket var ticket_btn = $j('<a>', { href: '#', onClick: 'ticket_modal(this)' }); ticket_btn.append($j('<i>', { 'class': 'fa fa-ticket ticket-submit-btn', 'html': '&nbsp;Submit&nbsp;Ticket' })); // copy data attributes into the ticket button so it can be accessed when showing the popup modal ticket_btn.data('log', restore.log); ticket_btn.data('title', title); ticket_btn.data('params', restore.params); ticket_btn.data('tag', restore.tag); ticket_btn.data('task', restore.task); if (window.tickets_submitted.indexOf(restore.tag) != -1) { ticket_btn.css('color', '#666'); ticket_btn.data('sent', 'y'); ticket_area.addClass('ticket-submitted alert alert-success'); ticket_area.append($j('<i>', { 'class': 'fa fa-check-circle ticket-success-icon' })); ticket_area.append('A ticket was submitted with the log file for troubleshooting'); } btn_grp.append(ticket_btn); btn_grp.append(log_btn); } btn_grp.append(cancel_btn); bottom.append(ticket_area); bottom.append(btn_grp); var div = $j('<div>', { 'class': 'well restore-well' }); div.append(top); div.append(bottom); return div; } /* rudimentary check for trying to escape homedir. * the backend will do a better check later */ function good_path(path) { path = path.replace(/^\/+/, '').replace(/\/+$/, '').split('/'); var backs = 0; var forwards = 0; for (var i = 0; i < path.length; i++) { if (path[i] == '..') { backs += 1; } else { forwards += 1; } } return forwards >= backs; } /* runs whenever a dump path is changed */ function check_path(input) { input = $j(input); var err_div = $j(input.data('check-error')); if (good_path(input.val())) { err_div.hide(); } else { err_div.show(); } } /* displays a log viewer when "View Fail Log" is clicked on a restore */ function view_fail_log(link) { link = $j(link); var div = $j('#log-modal-body'); div.empty(); $j.each(link.data('log'), function(e_id, entry) { var date = stamp_to_human(entry[0], true) var msg = entry[1]; var p = $j('<p>'); p.append($j('<strong>', { text: date })); p.append(' '.concat(msg)); div.append(p); }); $j('#log-modal').modal('show'); } /* Shows the "Submit Ticket" popup modal */ function ticket_modal(link) { link = $j(link); var tag = link.data('tag'); if (link.data('sent') == 'y') { return; } if (window.tickets_submitted.indexOf(tag) != -1) { return; } // access data attrs of the link and place them on the modal before showing var log = link.data('log'); var title = link.data('title'); var params = link.data('params'); var task = link.data('task'); var modal = $j('#ticket-modal'); $j('#ticket-do-btn').prop('disabled', false); $j('#ticket-do-btn').text('Submit Ticket'); $j('#ticket-error').hide(); modal.data('tag', tag); modal.data('task', task); modal.data('log', log); modal.data('title', title); modal.data('params', params); modal.modal('show'); } /* when "Submit Ticket" is clicked in the popup modal, this emails support */ function make_ticket() { var modal = $j('#ticket-modal') var log = modal.data('log'); var title = modal.data('title'); var task = modal.data('task'); var backup_params = modal.data('params'); var tag = modal.data('tag'); $j('#ticket-do-btn').prop('disabled', true); $j('#ticket-do-btn').text('Please wait...'); var params = { title: title, task: task, ipaddr: window.remote_ip, log: log, params: backup_params, msg: $j('#ticket-body').val() }; do_post('make_ticket', params, function(data) { if (data.status == 0) { window.tickets_submitted.push(tag); $j('.ticket-submit').each(function(index, alert) { // show the success message alert = $j(alert); if (alert.data('tag') == tag) { alert.empty(); alert.addClass('ticket-submitted alert alert-success'); alert.append($j('<i>', { 'class': 'fa fa-check-circle ticket-success-icon' })); alert.append('A ticket was submitted with the restore log for troubleshooting'); } }); $j('.ticket-submit-btn').each(function(index, btn) { // disable the button btn = $j(btn); if (btn.data('tag') == tag) { btn.css('color', '#666'); btn.data('sent', 'y'); } }); modal.modal('hide'); $j('#ticket-body').val(''); } else { console.log(data); $j('#ticket-error').show(); } }); } /* update a progress-bar div */ function set_bar(elem, numerator, denominator, show_msg) { if (numerator == '?') { // we were not able to fetch dir sizes from cPanel // and the customer selected for custom backups elem.css('background-color', 'orangered'); elem.css('width', '100%'); elem.text("Data Unavailable"); return; } if (denominator == 0) { if (show_msg) { elem.text('DISABLED'); } var percent = 100; } else if (numerator > denominator) { if (show_msg) { elem.text('OVER QUOTA'); } var percent = 100; } else { elem.text(''); var percent = numerator / denominator * 100 } if (percent <= 30) { var color = 'green'; } else if (percent <= 50) { var color = 'goldenrod'; } else if (percent <= 80) { var color = 'orangered'; } else { var color = 'red'; } elem.css('background-color', color); elem.css('width', String(percent).concat('%')); } /* then the cancel button next to an ongoing restore is clicked */ function cancel_restore_item(link) { link = $j(link); var well = link.closest('.well'); do_post('cancel_restore', { tag: link.data('tag') }, function(data) { if (data.status == 0) { update_restore_queues(); } }); } /* calculate homedir selection size, return '?' or a number in GB */ function calc_home_usage() { if (!get_switch_state('homedir_enabled')) { $j('#homedir-apply-btn').prop('disabled', false); console.log('homedir disabled, so its size is 0MB'); return 0; // disabled } var home_mode = $j('input[name=mode_homedir]:checked').val(); if (home_mode == 'whitelist') { var homedir_mb = 0; var included = get_browser_selected('#homedir-include-browser'); $j('#homedir-apply-btn').prop('disabled', included.length == 0); var all_sizes = $j('#homedir-include-browser').data('all-sizes'); $j.each(included, function(index, included_item) { if (!(included_item in all_sizes)) return '?'; if (all_sizes[included_item] === null) return '?'; homedir_mb += all_sizes[included_item]; }); console.log('homedir whitelist total: '.concat(homedir_mb).concat('MB')); return homedir_mb; } else if (home_mode == 'blacklist') { var homedir_mb = $j('#homedir-size').data('homedir-size'); var quotactl_mb = homedir_mb; if (homedir_mb == '?') return '?'; var excluded = get_browser_selected('#homedir-exclude-browser'); $j('#homedir-apply-btn').prop('disabled', excluded.length == 0); var all_sizes = $j('#homedir-exclude-browser').data('all-sizes'); $j.each(excluded, function(index, excluded_item) { if (!(excluded_item in all_sizes)) return '?'; if (all_sizes[excluded_item] === null) return '?'; homedir_mb -= all_sizes[excluded_item]; }); console.log('homedir size after blacklist: '.concat(homedir_mb).concat('MB (quotactl was ').concat(quotactl_mb).concat('MB)')); return homedir_mb; } else { // entire homedir selected $j('#homedir-apply-btn').prop('disabled', false); var homedir_mb = $j('#homedir-size').data('homedir-size'); if (homedir_mb == '?') return '?'; console.log('homedir size from quotactl is '.concat(homedir_mb).concat('MB')); return homedir_mb; } } /* set the total usage bar at the top of the page from usage in mb */ function recalculate_usage() { var total_gb_span = $j('#total_gb'); var avail_gb_span = $j('#avail_gb'); var quota_mb = Number(total_gb_span.data('quota-mb')); var srv_unused = total_gb_span.data('srv-unused'); var mb_usage = 0; // Add homedir usage var homedir_mb = calc_home_usage(); // update totals under custom selections for homedir $j('.total-selected-homedir').text(to_gb(homedir_mb)); $j('.usage_gb_homedir').text(to_gb(homedir_mb)); if (homedir_mb === '?') { mb_usage = '?'; } else { mb_usage += homedir_mb; } // Add MySQL and PgSQL usage $j.each(['mysql', 'pgsql'], function(i, dbtype) { var dbase_mode = $j('input[name=mode_'.concat(dbtype).concat(']:checked')).val(); if (dbase_mode != undefined) { // it's on the page if (!get_switch_state(dbtype.concat('_enabled'))) { console.log(dbtype.concat(' disabled, so its size is 0MB')); var dbase_mb = 0; // disabled $j('#'.concat(dbtype).concat('-apply-btn')).prop('disabled', false); } else if (dbase_mode == 'whitelist') { var dbase_mb = get_custom_db_usage(dbtype, true); console.log(dbtype.concat(' whitelist total: '.concat(dbase_mb).concat('MB'))); } else if (dbase_mode == 'blacklist') { var total_all_dbs = get_custom_db_total(dbtype); if (total_all_dbs != '?') { var dbase_mb = total_all_dbs - get_custom_db_usage(dbtype, false); } else { var dbase_mb = '?'; } console.log(dbtype.concat(' size after blacklist: ').concat(dbase_mb).concat('MB (total was ').concat(total_all_dbs).concat('MB)')); } else { // all databases $j('#'.concat(dbtype).concat('-apply-btn')).prop('disabled', false); var dbase_mb = get_custom_db_total(dbtype); console.log(dbtype.concat(' total (all) is ').concat(dbase_mb).concat('MB')); } // update totals under custom selections for databases $j('.total-selected-'.concat(dbtype)).text(to_gb(dbase_mb)); $j('.usage_gb_'.concat(dbtype)).text(to_gb(dbase_mb)); if (mb_usage != '?') { mb_usage += dbase_mb; } } }); // If the child accounts tab is shown, update the usage for the parent var parent_usage = $j('#parent_usage'); if (parent_usage.length > 0) { // it exists parent_usage.text(to_gb(mb_usage)); parent_bar = $j('#parent_progressbar'); set_bar(parent_bar, mb_usage, quota_mb, true); if (mb_usage != '?') { mb_usage += get_child_total(); } } // Set the total at the top total_gb_span.text(to_gb(mb_usage)); if (mb_usage == "?") { avail_gb_span.text("?"); } else { var avail = quota_mb - mb_usage; if (srv_unused != undefined && srv_unused < avail) { avail = srv_unused; } if (avail < 0) { avail = Math.abs(avail); $j('#avail_denominator').hide(); $j("#avail_lbl").text(" more GB needed"); } else { $j('#avail_denominator').show(); $j("#avail_lbl").text("GB remain"); } avail_gb_span.text(to_gb(avail)); } // Update each bar shown under custom selections in the settings tab $j('.total-selected-bar').each(function(b_index, bar) { set_bar($j(bar), mb_usage, quota_mb, true); }); // If over quota, also show a warning div beneath the total bar and // within any custom selections that are expanded if (mb_usage > quota_mb) { $j('#total-incalculable-warning').hide(); $j('#total-over-quota-warning').show(); $j('#over-quota-hover').css('display', 'inline'); $j('.total-selected-warning').show(); } else if (mb_usage == "?") { $j('#total-incalculable-warning').show(); $j('#total-over-quota-warning').hide(); $j('#over-quota-hover').hide(); $j('.total-selected-warning').hide(); } else { $j('#total-incalculable-warning').hide(); $j('#total-over-quota-warning').hide(); $j('#over-quota-hover').hide(); $j('.total-selected-warning').hide(); } } /* get the usage of a all selected items for a given database backup type and whether * we're counting for a whitelist (or blacklist) */ function get_custom_db_usage(baktype, whitelist) { if (whitelist) { var inputs = $j('#custom_items_whitelist_'.concat(baktype).concat(' input')); } else { var inputs = $j('#custom_items_blacklist_'.concat(baktype).concat(' input')); } var size_mb = 0; var num_checked = 0; var error = false; $j.each(inputs, function(i, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { num_checked += 1; var this_size = checkbox.data('size'); if (this_size == '?') { error = true; } else { size_mb += Number(this_size); } } }); $j('#'.concat(baktype).concat('-apply-btn')).prop('disabled', num_checked == 0); if (error) return '?'; return size_mb; } /* get the total size of all db items for custom backups if all were selected */ function get_custom_db_total(baktype) { var size_mb = 0; var error = false; $j.each($j('#custom_items_whitelist_'.concat(baktype).concat(' input')), function(i, checkbox) { var this_size = $j(checkbox).data('size'); if (this_size == '?') { error = true; } else { size_mb += Number(this_size); } }); if (error) return '?'; return size_mb; } /* get the state of a cpanel enable/disable switch without needing AngularJS */ function get_switch_state(id) { return $j("#".concat(id)).hasClass('switch-on'); } /* set the state of a cpanel enable/disable switch without needing AngularJS */ function set_switch_state(id, enabled) { var divs = $j(".switchdiv_".concat(id)); if (divs.hasClass('disabled')) { enabled = false; } var label = $j("#switchlabel_".concat(id)); if (enabled) { divs.removeClass('switch-off'); divs.addClass('switch-on'); label.text(label.data('enabled-text')); } else { divs.removeClass('switch-on'); divs.addClass('switch-off'); label.text(label.data('disabled-text')); } } /* When the "Restore" link is clicked in the settings tab, this takes the user to that section of the restore tab and auto-selects that date */ function goto_restore(link) { link = $j(link); var baktype = link.data('baktype'); var geo = link.data('geo'); if (baktype == 'homedir') { // the change event will already init the file browser, so // if this is the first time expanding, avoid initializing it twice window.homedir_restore_shown_once = true; } var collapse = $j('#restore_'.concat(baktype).concat('_collapse')); var val = ''.concat(geo).concat(':').concat(link.data('snap')); collapse.find('.restore-date-select').val(val).change(); // hide all other accordion items on the restore form $j.each($j('#restore_tab .collapse'), function(i, elem) { elem = $j(elem); if (collapse.attr('id') != elem.attr('id')) { elem.collapse('hide'); } }); collapse.collapse('show'); // show this accordion item $j('#nav-link-restore').tab('show'); } /* flip the state of a cpanel enable/disable switch without needing AngularJS */ function toggle_switch_state(id) { var enabled = !get_switch_state(id); set_switch_state(id, enabled); if (id.endsWith('_enabled')) { var baktype = id.split('_', 1)[0]; apply_settings(baktype, '#'.concat(baktype).concat('apply-btn')); } set_child_usage(); // update child progress bars show_hide_baktypes(); // show/hide any backup forms if necessary recalculate_usage(); // adjust quotas for anything that changed show_hide_child_cols(); // hide child account form columns if needed update_sched(); // update scheduling column if it disabled something if (id.startsWith('childnotify-')) { validate_child_email(); } if (id == 'do_child_limits') { // submit on toggle if this is the enable button at the top of // the child account form check_overprovision(); apply_child_limits(false); } } /* convert MB to GB and round 2 decimal points; return as a string */ function to_gb(mb) { if (mb === '?') { return '?'; } return (Math.round(Number(mb / 1024) * 100) / 100).toFixed(2); } /* Different dates may have different databases backed up. * This populates the database select dropdown whever the date * is changed in the restore form */ function update_restore_dbnames() { $j('.restore_db_date').each(function(index, date_select) { var date_select = $j(date_select); var dbtype = date_select.data('baktype'); var date_option = date_select.find(":selected"); var dbname_select = $j('#restore_dbname_'.concat(dbtype)); dbname_select.find('option').remove(); dbname_select.append($j('<option>', { text: 'select', value: '' })); var geo = date_option.data('geo'); $j.each(date_option.data('dbsnaps'), function(dbname, snap_id) { dbname_select.append($j('<option>', { value: "".concat(geo).concat(":").concat(snap_id), text: dbname })); }); }); } function update_geo_dests() { var geo_loc = $j('#restore_accordion').data('geo-loc'); var cluster_loc = $j('#restore_accordion').data('cluster-loc'); $j('.restore-date-select').each(function (index, select) { var select = $j(select); var baktype = select.data('baktype'); var geo = select.find(":selected").data('geo'); if (geo == 1) { $j("#geo-dest-".concat(baktype)).text(geo_loc); } else { $j("#geo-dest-".concat(baktype)).text(cluster_loc); } }); } /* only show custom lists under radio buttons which are selected and update the "data backed up" column on the header */ function show_hide_custom() { $j('.apply-msg').hide(); // hide save mesages; form was just changed $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { var checked = $j('input[name=mode_'.concat(baktype).concat(']:checked')).val() if (checked != undefined) { var white_div = $j('#custom_hide_whitelist_'.concat(baktype)); var black_div = $j('#custom_hide_blacklist_'.concat(baktype)); if (checked == 'whitelist') { white_div.show(); black_div.hide(); $j('#mode_descr_'.concat(baktype)).text('Custom'); } else if (checked == 'blacklist') { white_div.hide(); black_div.show(); $j('#mode_descr_'.concat(baktype)).text('Custom'); } else { white_div.hide(); black_div.hide(); if (get_switch_state(baktype.concat('_enabled'))) { $j('#mode_descr_'.concat(baktype)).text('All Data'); } else { $j('#mode_descr_'.concat(baktype)).text('Disabled'); } } } }); } /* show only backup types which are enabled in the settings tab */ function show_hide_baktypes() { $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { if ($j('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists var enabled = get_switch_state(baktype.concat('_enabled')); if (enabled) { $j('#settings_form_'.concat(baktype)).show(); $j('#settings_form_alert_'.concat(baktype)).hide(); } else { $j('#settings_form_'.concat(baktype)).hide(); $j('#settings_form_alert_'.concat(baktype)).show(); } } }); show_hide_custom(); } /* hides columns on the child account form when limiting them is disabled */ function show_hide_child_cols() { if ($j('#do_child_limits').length > 0) { // the form exists var enabled = get_switch_state('do_child_limits'); if (enabled) { $j('.child-limit-inputs').show(); } else { $j('.child-limit-inputs').hide(); } } } /* only show scheduling options (interval or days) below the radio button that's currently checked and update the "schedule" column on the header */ function update_sched() { $j('.apply-msg').hide(); // hide save mesages; form was just changed $j.each(['homedir', 'mysql', 'pgsql'], function(i, baktype) { if ($j('#'.concat(baktype).concat('_enabled')).length > 0) { // the form exists if (!get_switch_state(baktype.concat('_enabled'))) { $j('#sched_descr_'.concat(baktype)).text('Disabled'); } else if ($j('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') { // we're using interval-based scheduling $j('#sched_interval_form_'.concat(baktype)).show(); $j('#sched_daytime_form_'.concat(baktype)).hide(); var interval = $j('#sched_interval_'.concat(baktype)).val(); if (interval == 1) { $j('#sched_descr_'.concat(baktype)).text('Every Day'); } else { $j('#sched_descr_'.concat(baktype)).text('Every '.concat(interval).concat(' Days')); } } else { // we're using day/time-based scheduling $j('#sched_interval_form_'.concat(baktype)).hide(); $j('#sched_daytime_form_'.concat(baktype)).show(); var hour = $j('#scheduling_hour_'.concat(baktype)).val(); var meridiem = $j('#scheduling_meridiem_'.concat(baktype)).val(); var day_labels = []; $j.each($j('#scheduling_days_'.concat(baktype).concat(' input')), function(ii, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { day_labels.push(checkbox.data('short')); } }); if (day_labels.length == 0) { day_labels = '?'; // no days are selected yet } else { day_labels = day_labels.join(', '); } $j('#sched_descr_'.concat(baktype)).text( day_labels .concat(' | ') .concat(hour) .concat(meridiem) ); } } }); } /* Set the "current usage" column of the child tab */ function set_child_usage() { var quota_mb = $j('#total_gb').data('quota-mb'); $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(row_div); var usage = row_div.find('.childacct-usage').data('usage'); if (usage != undefined) { row_div.find('.usage_span').text(to_gb(usage)); } else { usage = 0; } var bar = row_div.find('.childacct-progressbar'); if (get_switch_state('do_child_limits')) { // limits turned on var limit = row_div.find('.childacct-limit').val(); var limit_span = row_div.find('.limit_span'); limit_span.text('/ '.concat(limit).concat('GB')); limit_span.show(); set_bar(bar, usage, limit * 1024, true); } else { // limits turned off; denominator is total quota set_bar(bar, usage, quota_mb, true); row_div.find('.limit_span').hide(); } }); } /* calculate total size of child accounts */ function get_child_total() { var total = 0; var limits_on = get_switch_state('do_child_limits'); $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(row_div); // usage in MB for this one child var this_usage = row_div.find('.childacct-usage').data('usage'); if (this_usage != undefined) { if (limits_on) { var this_limit = Number(row_div.find('.childacct-limit').val()) * 1024; if (this_limit < this_usage) { total += this_limit; } else { total += this_usage; } } else { total += this_usage; } } }); return total; } /* cancel button on the bottom of a restore form * (not the button to cancel a requested restore that's already going) */ function cancel_restore_form(cancel_link) { var collapse = $j(cancel_link).closest('.collapse'); var restore_dbname_select = collapse.find('.restore_dbname_select'); if (restore_dbname_select.length > 0) { // this is a database restore form restore_dbname_select.val(''); } else { // this is the homedir restore form $j('#homedir_filebrowser :input').prop('checked', false); window.homedir_restore_shown_once = false; // reset to as if we never saw this form } var alert_div = collapse.find('.restore_alert'); var msg_div = collapse.find('.restore_alert_msg'); alert_div.removeClass('alert alert-danger'); msg_div.addClass('hidden'); msg_div.removeClass('restore_alert_msg_shown'); collapse.collapse('hide'); } /* save button on the child account tab */ function apply_child_limits(from_submit_btn) { if (!validate_child_email()) { if (from_submit_btn) { show_msg(false, 'child-limit-apply-msg', 'invalid email'); } return; } if (from_submit_btn) { $j('#child-limit-apply-button').prop('disabled', true); } var email_err = $j('#child-notify-invalid-email'); var params = {}; var child_email = $j('#child-limit-email').val(); if (child_email.length > 0) { params['email'] = child_email; } if (get_switch_state('do_child_limits')) { params['do_limit'] = '1'; } else { params['do_limit'] = '0'; } if (params['do_limit'] == '1') { params['default_limit'] = $j('#child_limit_default').val(); var limits = {}; var notifs = {}; $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(row_div); var name = row_div.find('.child-name').text(); limits[name] = row_div.find('.childacct-limit').val(); if (get_switch_state(row_div.find('.cjt2-toggle-switch').data('switch-id'))) { notifs[name] = '1'; } else { notifs[name] = '0'; } }); params['limits'] = limits; params['notifs'] = notifs; } do_post('set_child_limits', params, function(data) { if (from_submit_btn) { if (data.status != 0) { show_msg(false, 'child-limit-apply-msg', data.error); } else { show_msg(true, 'child-limit-apply-msg', 'applied'); } $j('#child-limit-apply-button').prop('disabled', false); } else { if (data.status != 0) { show_msg(false, 'child-limit-toggle-msg', data.error); } } }); } /* performs AJAX calls */ function do_post(action, args, func) { console.log( 'Posting: ' .concat(action).concat(' ') .concat(JSON.stringify(args)) ); $j.ajax({ url: './post.live.php', type: 'post', timeout: 120 * 1000, data: { action: action, args: JSON.stringify(args) } }) .done(function(data) { try { data = JSON.parse(data); } catch (err) { console.log(data); console.log(err); data = { status: 1, error: 'error - invalid JSON from server' } } console.log(data); func(data) }) .fail(function(xhr, statusText, errorThrown) { if (xhr.state() == 'rejected') { data = { status: 1, error: 'Sorry, your settings could not be saved at this time as your session has expired. Please log back in and try again.' } } else { console.log(errorThrown); data = { status: 1, error: 'error - '.concat(statusText) } } func(data) }); } /* save buttons on the settings tab */ function apply_settings(baktype, button) { $j('.apply-msg').hide(); button = $j(button); button.prop('disabled', true); var params = { baktype: baktype }; if (get_switch_state(baktype.concat('_enabled'))) { // backups enabled params['enable'] = '1'; params['mode'] = $j('input[name=mode_'.concat(baktype).concat(']:checked')).val(); } else { // backups disabled params['enable'] = '0'; params['mode'] = 'all'; } if (baktype == 'homedir') { if (params['mode'] == 'whitelist') { params['custom'] = get_browser_selected('#homedir-include-browser'); } else if (params['mode'] == 'blacklist') { params['custom'] = get_browser_selected('#homedir-exclude-browser'); } else { params['custom'] = null; } } else { // database backups if (params['mode'] == 'whitelist') { var inputs = $j('#custom_items_whitelist_'.concat(baktype).concat(' input')); params['custom'] = []; $j.each(inputs, function(inp_index, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { params['custom'].push(checkbox.val()); } }); } else if (params['mode'] == 'blacklist') { var inputs = $j('#custom_items_blacklist_'.concat(baktype).concat(' input')); params['custom'] = []; $j.each(inputs, function(inp_index, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { params['custom'].push(checkbox.val()); } }); } else { var inputs = []; params['custom'] = null; } } if (params['custom'] != null && params['custom'].length == 0) { show_msg(false, baktype.concat('-apply-msg'), 'Nothing selected to backup'); button.prop('disabled', false); return; } if ($j('input[name=scheduling_'.concat(baktype).concat(']:checked')).val() == 'interval') { // using interval scheduling params['use_interval'] = '1'; params['interval'] = $j('#sched_interval_'.concat(baktype)).val(); } else { // using day/time scheduling params['use_interval'] = '0'; params['hour'] = $j('#scheduling_hour_'.concat(baktype)).val(); params['meridiem'] = $j('#scheduling_meridiem_'.concat(baktype)).val(); params['days'] = []; $j.each($j('#scheduling_days_'.concat(baktype).concat(' input')), function(day_index, checkbox) { checkbox = $j(checkbox); if (checkbox.is(':checked')) { params['days'].push(checkbox.val()); } }); } do_post('set_settings', params, function(data) { if (data.status != 0) { show_msg(false, baktype.concat('-apply-msg'), data.error); } else { show_msg(true, baktype.concat('-apply-msg'), 'applied'); } button.prop('disabled', false); }); } /* "Restore" button on the restore tab; redirects to either * do_homedir_restore or do_db_restore */ function do_restore(baktype, button) { if (baktype != 'homedir' && $j('#restore_dbname_'.concat(baktype)).val().length == 0) { // database restore with no db selected $j('#no_db_'.concat(baktype)).show(); return; } var email = $j('#'.concat(baktype).concat('-restore-email')).val(); if (email.length > 0 && !CPANEL.validate.email(email)) { return; // invalid email entered } button = $j(button); var alert_div = $j('#restore_alert_'.concat(baktype)); var msg = $j('#restore_alert_msg_'.concat(baktype)); if (msg.hasClass('hidden')) { alert_div.addClass('alert alert-danger'); msg.removeClass('hidden'); msg.addClass('restore_alert_msg_shown'); $j('#'.concat(baktype).concat('-restore-msg')).hide(); } else { alert_div.removeClass('alert alert-danger'); msg.addClass('hidden'); msg.removeClass('restore_alert_msg_shown'); button.prop('disabled', true); if (baktype == 'homedir') { do_homedir_restore(button); } else { do_db_restore(baktype, button); } } } /* requests home directory restores */ function do_homedir_restore(button) { if (all_selected('#homedir_filebrowser')) { var paths = [$j('#restore_tab').data('home-path')]; } else { var paths = get_browser_selected('#homedir_filebrowser'); } var params = { // list of full paths paths: paths, date: $j('#restore_date_homedir option:selected').data('stamp'), geo: parseInt($j('#restore_date_homedir').val().substr(0, 1)), snap: $j('#restore_date_homedir').val().substr(2), // target path will not include the /home/user/ part target: $j('#dump_path_homedir').val(), mode: $j('[name="restore_method_homedir"]:checked').val(), email: $j('#homedir-restore-email').val() }; do_post('homedir_restore', params, function(data) { if (data.status != 0) { show_msg(false, 'homedir-restore-msg', data.error); } else { button.closest('.collapse').collapse('hide'); update_restore_queues(); setTimeout( // delay so the collapse has time to finish function() { show_msg(true, 'homedir-restore-msg', 'Queued'); }, 1000 ); } button.prop('disabled', false); }); } /* requests database restores */ function do_db_restore(baktype, button) { var params = { date: $j('#restore_date_'.concat(baktype)).val().substr(2), dbname: $j('#restore_dbname_'.concat(baktype).concat(' option:selected')).text(), geo: parseInt($j('#restore_dbname_'.concat(baktype)).val().substr(0, 1)), snap: $j('#restore_dbname_'.concat(baktype)).val().substr(2), // path will not include the /home/user/ part target: $j('#dump_path_'.concat(baktype)).val(), mode: $j('[name="restore_method_'.concat(baktype).concat('"]:checked')).val(), email: $j('#'.concat(baktype).concat('-restore-email')).val() }; do_post(baktype.concat('_restore'), params, function(data) { if (data.status != 0) { show_msg(false, baktype.concat('-restore-msg'), data.error); } else { button.closest('.collapse').collapse('hide'); update_restore_queues(); setTimeout( // delay so the collapse has time to finish function() { show_msg(true, baktype.concat('-restore-msg'), 'Queued'); }, 1000 ); } button.prop('disabled', false); }); } /* disables toggles for notifications for children when their limit * is set to 0, because that would be redundant */ function child_notif_disable() { $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(row_div); var notif_toggle = row_div.find('.cjt2-toggle-switch'); if (Number(row_div.find('.childacct-limit').val()) <= 0) { set_switch_state(notif_toggle.data('switch-id'), false); notif_toggle.addClass('disabled'); } else { notif_toggle.removeClass('disabled'); } }); } /* called when item selection on the homedir restore widget changes */ function enable_home_restore(has_items) { $j('#restore-btn-homedir').prop('disabled', !has_items); } /* all cancel buttons on the settings tab */ function cancel_settings(cancel_link) { var collapse = $j(cancel_link).closest('.collapse'); // set enable/disable back to what it was on page load var oldval_span = collapse.find('.oldval-enable'); if (oldval_span.data('oldval') == 'y') { set_switch_state(oldval_span.data('enableid'), true); } else { set_switch_state(oldval_span.data('enableid'), false); } // set the scheduling back collapse.find('.sched_radio[data-oldval]').prop('checked', true).trigger('change'); collapse.find('.sched_hour').val(collapse.find('.sched_hour').data('oldval')); collapse.find('.sched_days_checkbox[data-oldval="n"]').prop('checked', false); collapse.find('.sched_days_checkbox[data-oldval="y"]').prop('checked', true); collapse.find('.sched_meridiem[data-oldval]').prop('checked', true).trigger('change'); // AM/PM // set the mode and selections back collapse.find('.custom_checkbox[data-oldval="n"]').prop('checked', false); collapse.find('.custom_checkbox[data-oldval="y"]').prop('checked', true); collapse.find('.custom_radio[data-oldval]').prop('checked', true).trigger('change'); // hide this form collapse.collapse('hide'); } /* shows a message next to a save button */ function show_msg(success, id, msg) { $j('#'.concat(id).concat(' span')).text(msg); var div = $j('#'.concat(id)); if (success) { div.removeClass('alert-danger'); div.addClass('alert-success'); } else { div.removeClass('alert-success'); div.addClass('alert-danger'); } div.show(); } function check_overprovision() { var total = 0; $j('.childacct-limit').each(function(i, lim) { total += Number($j(lim).val()) * 1024; }); var do_limit = get_switch_state('do_child_limits'); var quota = Number($j('#total_gb').data('quota-mb')); if (do_limit && total > quota) { $j('#overprovision-warn').show(); $j('.childacct-limit').addClass('overprov'); $j('#child-limit-apply-button').prop('disabled', true); } else { $j('#overprovision-warn').hide(); $j('.childacct-limit').removeClass('overprov'); $j('#child-limit-apply-button').prop('disabled', false); } } /* when select/deselect all is clicked in custom items */ function custom_db_selectall(div_id, checked) { $j(div_id.concat(' input')).each(function(index, item) { $j(item).prop('checked', checked); }); } /* rigged to keyup on email inputs */ function validate_email(input) { input = $j(input); email = input.val(); var err = $j(input.data('err')); if (input.attr('id') == 'child-limit-email') { // email is required if notifications are on for child accounts validate_child_email(); } else { // email can be empty if (email.length == 0 || CPANEL.validate.email(email)) { err.hide(); } else { err.show(); } } } function validate_child_email() { var addr = $j('#child-limit-email').val(); var err = $j('#child-notify-invalid-email'); var notifs_on = false; $j.each($j('.childacct-row'), function(i, row_div) { row_div = $j(row_div); if (get_switch_state(row_div.find('.cjt2-toggle-switch').data('switch-id'))) { notifs_on = true; } }); if (!notifs_on) { err.hide(); return true; } if (addr.length > 0 && CPANEL.validate.email(addr)) { err.hide(); return true; } else { err.show(); return false; } } function stamp_to_human(stamp, show_min) { /* converts a timestamp to a human readable format */ var $date = new Date(1000 * stamp); var $hour = $date.getHours(); if ($hour == 0) { $hour = '12'; var $end = 'AM'; } else if ($hour == 12) { var $end = 'PM'; } else if ($hour < 12) { var $end = 'AM'; } else { $hour -= 12; var $end = 'PM'; } var short_months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; var $out = short_months[$date.getMonth()] .concat(' ') .concat($date.getDate()) .concat(', ') .concat($date.getFullYear()) .concat(' ') .concat($hour); if (show_min) { $out = $out.concat(':').concat($date.getMinutes()); } $out = $out.concat($end); return $out; } function finish_loading() { var div = $j('#loading-div') if (div.length == 0) return; if (div.data('restores-loaded') == 1 && div.data('main-loaded') == 1) { $j('#loading-div').remove(); } } function fix_dates() { $j.each($j('.fix-locale-stamp'), function(index, element) { element = $j(element); element.text(stamp_to_human(element.text(), false)); }); $j.each($j('.fix-opt-locale-stamp'), function(index, element) { element = $j(element); var orig = element.text(); if (orig.includes(" - ")) { // coast - stamp var coast = orig.split(' - ')[0]; var date = stamp_to_human(orig.split(' - ')[1], false); element.text(coast.concat(' - ').concat(date)); } else { // just stamp element.text(stamp_to_human(orig, false)); } }); } $j(document).ready(function() { // Fix labels timestamps -> locale time fix_dates(); $j('.help').popover({ trigger: 'focus' }); window.tickets_submitted = []; // hide warnings about short intervals until needed $j('.interval-error').hide(); // hide restore queue columns until we have something to show $j('#restore_queue_div').hide(); // setup the queue timer span var countdown_span = $j('#restore_queue_timer'); countdown_span.data('timer', countdown_span.data('dur')); // show any ongoing restores if they exist update_restore_queues(); // add overprovisioning warnings in child account tab if needed check_overprovision(); // hide all error-msg divs until they are needed $j('.error-msg').hide(); // when dump paths are changed, check validity $j('.path-check').bind('keyup', function() { check_path(this); }); // ... but hide the errors initially $j('.path-error').hide(); // validate emails entered $j('.validate-email').bind('keyup', function() { validate_email(this); }); if ($j('#child-limit-email').val() != undefined) { validate_child_email(); } window.homedir_restore_shown_once = false; // set the "current usage" column of the child tab set_child_usage(); if ($j('#restore-btn-homedir').length > 0) { // disable the homedir restore button until the file browser enables it $j('#restore-btn-homedir').prop('disabled', true); } // handles when an accordion header is clicked $j('.collapse').on('show.bs.collapse', function(event) { var target_id = $j(event.target).attr('id'); // hide all other accordions $j('.collapse:not(#'.concat(target_id).concat(')')).collapse('hide'); $j(event.target).closest('.panel').find('.arw').html('&#9660;'); if (!window.homedir_restore_shown_once && target_id == 'restore_homedir_collapse') { // if this is the first time the homedir restore accordion is shown, initialize the file browser window.homedir_restore_shown_once = true; var geo = parseInt($j('#restore_date_homedir').val().substr(0, 1)); var snap = $j('#restore_date_homedir').val().substr(2); init_file_browse('#homedir_filebrowser', snap, geo); } }); // setup homedir settings file browsers init_file_browse('#homedir-include-browser'); init_file_browse('#homedir-exclude-browser'); $j('.collapse').on('hide.bs.collapse', function(event) { $j(event.target).closest('.panel').find('.arw').html('&#9658;'); }); // populate the database dropdown in restore forms update_restore_dbnames(); // and keep them updated when dates are changed $j('.restore_db_date').on('change', update_restore_dbnames); // Update #geo-dest-<baktype> if ($j('#restore_accordion').data('show-geo') == 1) { update_geo_dests(); $j('.restore-date-select').on('change', update_geo_dests); } // when db changes, hide error that none was selected (if it was shown) $j('.restore_dbname_select').on('change', function() { $j($j(this).data('no-db')).hide(); }); // ... but hide them until a restore request triggers them to be shown $j('.no-db-alert').hide(); // hide any backup types that are disabled from the settings form show_hide_baktypes(); // hide columns in the child account form if needed show_hide_child_cols(); // hide custom lists if their radio button is not clicked show_hide_custom(); // show/hide custom lists when the selection changes and recalculate usage $j('.custom_radio').on('change', function() { show_hide_custom(); recalculate_usage(); }); // when an item in a custom list changes, recalculate usage $j('.custom_checkbox').change(recalculate_usage); // show only the scheduling section that's currently selected update_sched(); // when scheduling mode is changed, show/hide the appropriate forms $j('.sched_radio, .sched_meridiem').on('change', update_sched); // update scheduling mode in the header when interval is changed $j('.sched_interval_input, .sched_hour').bind('keyup mouseup', update_sched); $j('.sched_interval_input').bind('keyup mouseup', function() { // if the interval is set to < 1, show a warning var input = $j(this); if (input.val() < 1) { $j(input.data('error-id')).show(); } else { $j(input.data('error-id')).hide(); } }); // when the limit for a child is changed $j('.childacct-limit').bind('keyup mouseup', function() { set_child_usage(); // set progress bars recalculate_usage(); // recalculate usage in case that changes the total child_notif_disable(); // disable notifications for children with a limit of 0 check_overprovision(); }); // update scheduling mode in the header when a day is checked or unchecked $j('.sched_days_checkbox').change(update_sched); // populate each usage progressbar recalculate_usage(); // re-initialize the file browser if date selection changes $j('#restore_date_homedir').on('change', function () { var geo = parseInt($j('#restore_date_homedir').val().substr(0, 1)); var snap = $j('#restore_date_homedir').val().substr(2); init_file_browse('#homedir_filebrowser', snap, geo); }); // disable notifications for any child accounts with a limit of 0 child_notif_disable(); $j('#over-quota-glyph').tooltip({ 'placement': 'top', 'title': 'Space needed exceeds your available space. Please purchase additional space or uncheck folders below.', }); update_sel_count(); var svr_total_bar = $j('#svr-total-bar'); if (svr_total_bar.length) { // if total server usage is showing set_bar(svr_total_bar, svr_total_bar.data('svr-usage'), svr_total_bar.data('svr-quota'), true); } $j('#loading-div').data('main-loaded', 1); finish_loading(); });